它可能会因为 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 位):考虑到 Z 中的位数,您必须不等距地分布 X 和 Y。基本上,对于立方体,您均匀分布:每个位在位置 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;
}