我如何有效地计算将单位立方体映射到其自身的反射和旋转?

问题描述 投票:2回答:1

对于基于八叉树的稀疏体素八叉树渲染器,我希望能够旋转并镜像八叉树的各个节点。尽管它实际上不是八叉树,但由于节点被共享并被允许将自己包含为子树。否则,我可以简单地将转换应用于八叉树本身。

在不失一般性的前提下,假定该多维数据集是一个单位多维数据集,其原点为一个角(0,0,0),而对角为(1,1,1)。我已经将立方体的角编码为3位整数。所以0(= 0b000)代表原点的角,1(= 0b001)代表(0,0,1)的角,而7(= 0b111)代表(1,1,1)的角。唯一允许的旋转和反射是围绕立方体的中心(1/2,½,½),这样拐角将以整数坐标结束。这意味着只有48种可能的转换。 (第一个角可以映射到8个可能的位置,下一个角可以映射到3个,第三个角可以映射到2个,这将固定其余角的位置。)

我还没有决定如何编码转换,尽管应该可以将其编码为单个32位整数(或者甚至是6位整数,因为只有48种可能的转换)。然后可以将变换用作函数,该函数将变换后的多维数据集的每个角映射到其位置。即

int transform(int corner, int transformation) {
  // magic happens here
  return result;
}

此外,我还应该具有合并转换的函数combine,以便transform(corner, combine(a,b))等于transform(transform(corner, b), a)

由于这些函数每秒将被调用十亿次,因此它们应该很快。虽然变换将被称为合并的大约4倍。该算法是递归的,因此,如果转换编码使用多个32位整数,则将其放入堆栈时会产生额外的运行时成本。

到目前为止,我已经发现问题可以分解为位翻转,这可以通过单个异或运算和位置换来完成(我尚不知道如何有效地完成)。但是,同时执行这两个操作的效率可能更高。

我打算在已经使用SSE4.1内部函数的C ++代码中使用它。尽管不使用内部函数或仅需要SSE3的解决方案是首选。最后,速度是最重要的。我将尝试使用http://quick-bench.com/比较解决方案。

((注意:我使用了affinetransform标记,因为没有正交转换标记,并且我不想创建它)。

c++ sse affinetransform isomorphism
1个回答
0
投票

您可以将转换存储为8个字节的数组,该数组对多维数据集角的排列进行编码。 transform方法就像数组查找一样简单。将这些转换中的两个转换组合在一起可以循环进行,但这会很慢。但是,事实证明SSSE3具有在单个指令中执行此操作的内在函数:_mm_shuffle_pi8

因此可以按如下方式实现必要的方法:

_mm_shuffle_pi8

根据我的基准测试结果,我得到了四次调用transform并合并一次的调用,这花费了大约2ns的CPU时间。这仍然有点慢,但是如果有足够的内核,这可能是可行的。


我还实现了一些不同的比较方法:

  • 将置换打包为int32中的半字节(4位整数),并使用循环来计算#include <tmmintrin.h> __m64 transform(int corner, __m64 transformation) { uint8_t array[8]; memcpy(array, &transformation, 8); // This call is optimized away by the compiler. return array[corner]; } __m64 combine(T a, T b) { return _mm_shuffle_pi8(b, a); } 的结果。使用一半的内存时,速度要慢3-5倍。
  • 直接由Milo Brandt提出的6位编码的工作。但是,我未能正确执行此操作。
  • 将允许的变换仅限制为轴对齐的反射的组合。可以使用按位XOR快速计算这些值。这大约快30-50%。

我创建了一个combine,尽管它不支持使用SSSE3指令,所以我不得不禁用使用quick-bench page的方法。您仍然可以在本地编译和运行它们。

© www.soinside.com 2019 - 2024. All rights reserved.