gpt4 book ai didi

c++ - 非立方区域的 Morton 曲线是 2 的幂

转载 作者:行者123 更新时间:2023-12-04 03:45:06 25 4
gpt4 key购买 nike

在优化光线追踪器时,我尝试使用 Morton 空间填充曲线改进交叉数据结构的数据局部性,但我的 3D 空间不是立方体(例如 512x512x256)。所有边都是 2 的幂,但并非所有边的长度都相同。

我一直无法找到边为 2 的幂的非正方形 Morton 曲线的任何示例。如果重要的话,我可以保证 x/y 轴的大小相同,只是 z 轴的长度不同。

enter image description here
请注意宽度是 2x 高度,但它也可以是 3x 或 4x 或任何其他。我一直无法找到执行此操作的方法。

理想情况下,解决方案会很快,因为 Morton 代码必须进行大量计算。所以我的问题是:如何为非立方空间生成空间填充莫顿曲线?这是专门针对 GPU (Cuda) 的。

维度上的条件是:
x, y, z 是二的幂
x == y
x, y >= z
或者如果更容易
x, y > z

最佳答案

它可能会因为 nz=11 而中断,但是对于 XY 正方形的一半大小它似乎对我有用

#include <cstdint>
#include <iostream>

static inline uint32_t spread(uint32_t x)
{
x = (x | (x << 10)) & 0x000F801F;
x = (x | (x << 4)) & 0x00E181C3;
x = (x | (x << 2)) & 0x03248649;
x = (x | (x << 2)) & 0x09249249;

return x;
}

static inline uint32_t morton(const uint32_t x, const uint32_t y, const uint32_t z)
{
return spread(x) << 0 | spread(y) << 1 | spread(z) << 2;
}


auto main() -> int {
int nx = 32;
int ny = 32;
int nz = 16;

for (int iz = 0; iz != nz; ++iz)
{
for (int iy = 0; iy != ny; ++iy)
{
for (int ix = 0; ix != nx; ++ix)
{
auto m = morton(ix, iy, iz);

std::cout << m << '\n';
}
}
}

return 0;
}

更新

如何使 Morton 代码适用于 256x256x64(8 位*8 位*6 位):您必须非等距离地展开 X 和 Y,同时考虑 Z 中的位数。基本上,对于立方体,您均匀地展开:位置上的每一位0, 3, 6, 9, 12, 15, 18, 21, 24,为正交轴上的其他两位留出空间。

所以立方体存在等距分布。但是对于从 Z 插入只有 6 位的情况,您必须有 6 个 3 的距离,但最后一个间隙没有 Z 位,因此 X 和 Y 扩展的最后一个间隙应该只有 1 位宽。因此,X 和 Y 的非等距分布。

沿线的东西:如果 Nx=Ny 是 XY 平面中的位数,并且 Nz!=Nx 或 Ny 是沿 Z 轴的位数,Nz 位的扩展间隙应为 2 位,剩余的间隙应为 1 位。因此有两个展开例程 - 一个用于具有非等距展开的 X&Y,现在取决于 Nz,另一个用于 Z 轴的展开函数。

好的,这是一个工作版本,似乎做对了

#include <cstdint>
#include <iostream>

#define func auto

func spreadZ(uint32_t v) -> uint32_t { // 2bit gap spread
v = (v | (v << 10)) & 0x000F801F;
v = (v | (v << 4)) & 0x00E181C3;
v = (v | (v << 2)) & 0x03248649;
v = (v | (v << 2)) & 0x09249249;

return v;
}

func spreadXY(const uint32_t v, const uint32_t bitsZ) -> uint32_t {
uint32_t mask_z = (1U << bitsZ) - 1U; // to mask bits which are going to have 2bit gap

uint32_t lo{ v & mask_z }; // lower part of the value where there are Z bits
lo = spreadZ(lo); // 2bit gap spread

uint32_t hi = v >> bitsZ; // high part of the value, 1bit gap

// 1bit gap spread
hi = (hi ^ (hi << 8)) & 0x00ff00ffU;
hi = (hi ^ (hi << 4)) & 0x0f0f0f0fU;
hi = (hi ^ (hi << 2)) & 0x33333333U;
hi = (hi ^ (hi << 1)) & 0x55555555U;

return lo + (hi << 3*bitsZ); // combine them all together
}

func morton(const uint32_t x, const uint32_t y, const uint32_t z, const uint32_t bitsZ) -> uint32_t {
return spreadXY(x, bitsZ) << 0 | spreadXY(y, bitsZ) << 1 | spreadZ(z) << 2;
}

func ispowerof2(const uint32_t n) -> bool {
return n && (!(n & (n - 1u)));
}

func bit_pos(const uint32_t n) -> uint32_t {
if (!ispowerof2(n))
throw -1;

uint32_t i{ 1u }, pos{ 1u };

while (!(i & n)) { // Iterate through bits of n till we find a set bit, i&n will be non-zero only when 'i' and 'n' have a same bit
i = i << 1; // unset current bit and set the next bit in 'i'

++pos; // increment position
}

return pos;
}

func main() -> int {
int nx = 256;
int ny = 256;

int nz = 256; //256...128...64...32...16...8...4...2...1 all works
int bitsZ = bit_pos(nz) - 1; // should be doing try/catch

for (int iz = 0; iz != nz; ++iz)
{
for (int iy = 0; iy != ny; ++iy)
{
for (int ix = 0; ix != nx; ++ix)
{
auto m = morton(ix, iy, iz, bitsZ);

std::cout << m << '\n';
}
}
}

return 0;
}

关于c++ - 非立方区域的 Morton 曲线是 2 的幂,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65313532/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com