/******************************************************************************/ /* Project - MudBun Publisher - Long Bunny Labs http://LongBunnyLabs.com Author - Ming-Lun "Allen" Chou http://AllenChou.net */ /******************************************************************************/ #ifndef MUDBUN_VOXEL_HASH_FUNCS #define MUDBUN_VOXEL_HASH_FUNCS #include "VoxelHashDefs.cginc" #include "AabbTreeFuncs.cginc" #include "BrushFuncs.cginc" #include "Math/Codec.cginc" #include "RenderModeDefs.cginc" #include "VoxelFuncs.cginc" // https://nosferalatu.com/SimpleGPUHashTable.html int register_alloc_top_node(float3 center, int3 iCenter) { float halfSize = 0.5f * currentNodeSize; uint key = top_node_key(iCenter); uint slot = key % nodeHashTableSize; int i = 0; while (i++ < kMaxVoxelHashCollisions) { uint prev = kNullVoxelHashKey; InterlockedCompareExchange(nodeHashTable[slot].key, kNullVoxelHashKey, key, prev); if (prev == kNullVoxelHashKey) { // newly registered int iNode = allocate_node(center, 0, -1, key); if (iNode < 0) { aNumNodesAllocated[0] = nodeHashTableSize; return -1; } nodeHashTable[slot].iNode = iNode; int prevNumAllocated = 0; InterlockedAdd(aNumAllocation[kNumAllocationsVoxelHash], 1, prevNumAllocated); if (renderMode == kRenderModeRayTracedVoxels) { int prevTopNodeAllocated = 0; InterlockedAdd(indirectDrawArgs[0], 36, prevTopNodeAllocated); } Aabb nodeAabb = make_aabb(center - halfSize, center + halfSize); nodePool[iNode].iBrushMask = allocate_node_brush_mask(iNode, nodeAabb); return iNode; } if (key == nodeHashTable[slot].key) { // already registered return -1; // already registered } else { // collision slot = (slot + 1) % nodeHashTableSize; } } return -1; } void register_brush_aabb(int iBrush) { int op = aBrush[iBrush].op; float blend = aBrush[iBrush].blend; float maxDistFromCenter = currentNodeSize + blend; int iProxy = aBrush[iBrush].iProxy; Aabb aabb = aabbTree[iProxy].aabb; float3 clampedSurfaceShift = max(-aabb_extents(aabb), surfaceShift); aabb.boundsMin.xyz -= clampedSurfaceShift; aabb.boundsMax.xyz += clampedSurfaceShift; int3 iBoundsMin = int3(floor(aabb.boundsMin.xyz / currentNodeSize)); int3 iBoundsMax = int3(floor(aabb.boundsMax.xyz / currentNodeSize)); float halfNodeSize = 0.5f * currentNodeSize; for (int z = iBoundsMin.z; z <= iBoundsMax.z; ++z) for (int y = iBoundsMin.y; y <= iBoundsMax.y; ++y) for (int x = iBoundsMin.x; x <= iBoundsMax.x; ++x) { if (enable2dMode && z != 0) continue; float3 center = (float3(x, y, z) + 0.5f) * currentNodeSize; // profiler says it's faster if we don't do this extra brush evaluation /* float d = sdf_brush(kInfinity, center, aBrush[iBrush]); if (op == kSdfUnion) { if (abs(d) > maxDistFromCenter) continue; } else if (op == kSdfSubtract) { if (d > maxDistFromCenter) continue; } else if (op == kSdfIntersect) { if (-d > maxDistFromCenter) continue; } */ register_alloc_top_node(center, int3(x, y, z)); } } int register_alloc_child_node(float3 center, float size, int depth, int iParent, uint3 childNodeCoord) { uint key = nodePool[iParent].key; key = concat_node_key(key, childNodeCoord); uint slot = key % nodeHashTableSize; int i = 0; while (i++ < kMaxVoxelHashCollisions) { uint prev = kNullVoxelHashKey; InterlockedCompareExchange(nodeHashTable[slot].key, kNullVoxelHashKey, key, prev); if (prev == kNullVoxelHashKey) { // newly registered int iNode = allocate_node(center, depth, iParent, key); if (iNode < 0) { aNumNodesAllocated[0] = nodeHashTableSize; return -1; } nodeHashTable[slot].iNode = iNode; return iNode; } if (key == nodeHashTable[slot].key) { // already registered return -1; } else { // collision slot = (slot + 1) % nodeHashTableSize; } } return -1; } #endif