Skip to content

Instantly share code, notes, and snippets.

@dwilliamson
Created December 19, 2019 12:22
Show Gist options
  • Save dwilliamson/681204e4e0d528925841ca8143609e55 to your computer and use it in GitHub Desktop.
Save dwilliamson/681204e4e0d528925841ca8143609e55 to your computer and use it in GitHub Desktop.
March To Surface
cmp_device_fn SamplePoint TryMarchToSurface(Texture3Du<short> tex_voxel_cache, RayMarch rm)
{
// Record an initial sample position for when locating the surface fails
SamplePoint initial_sample = rm.sample;
// Don't ray march if a normal couldn't be calculated
if (rm.ray_dir.x == (float)(1<<17))
return initial_sample;
// Want max traversal distance in terms of cells
// Don't increase this too much as it can force leaks in overhanging geometry
rm.max_dist_m = GPUOctreeNode_CellWidth(rm.gpu_node) * 3;
while (1)
{
// Check for cell exit conditions
if (rm.t_c >= rm.max_t_c)
{
// Walk to neighbouring nodes
enum WalkNodeResult result = RayMarch_WalkNodes(&rm);
switch (result)
{
case WalkNode_StopOutside: return rm.sample;
case WalkNode_StopInside: return initial_sample;
default: break;
}
}
// Lookup the slot offset each loop to keep register count lower
uint3 slot_offset = GPUOctreeNode_DistanceFieldSlot(rm.gpu_node, rm.nb_cells);
// Decompression won't shift the zero-point so can compare for leaving the surface directly
float d = SampleDistanceField(tex_voxel_cache, slot_offset, rm.sample.cell_pos_f);
if (d > 0)
return rm.sample;
// March along the ray, leaving at the max distance
if (!RayMarch_Step(&rm))
break;
}
return initial_sample;
}
cmp_kernel_fn void MarchToSurface(
Grid3D grid,
Texture3Du<short> tex_voxel_cache,
cmp_global GPUOctreeNode* gpu_nodes,
uint gpu_node_index,
cmp_global float3* normals,
cmp_global SamplePoint* out_positions)
{
// Turn the linear work group item index into a 3D index
int idx = cmp_thread_idx_x;
if (idx < Grid3D_GetNbItems(grid))
{
// Ray start position in cell-space, recontsructed from 3D index
int3 i = Grid3D_GetIndex(grid, idx);
SamplePoint sample;
sample.cell_pos_f.x = i.x;
sample.cell_pos_f.y = i.y;
sample.cell_pos_f.z = i.z;
sample.gpu_node_index = gpu_node_index;
sample.output_index = idx;
// Start the ray march along the field normal direction
float3 ray_dir = normals[idx];
RayMarch rm = RayMarch_New(32, gpu_nodes, sample, ray_dir, 0.25f, 0);
// We're also marching for the padding voxels outside the node bounds. These won't
// correctly march unless we make an initial step into the neighbouring nodes they're
// taken from.
RayMarch_WalkToNeighbours(&rm);
if (GPUOctreeNode_Type(rm.gpu_node) == OctreeNodeType_Field)
{
// Only march for valid nodes
sample = TryMarchToSurface(tex_voxel_cache, rm);
}
// March along the distance field normal direction
out_positions[idx] = sample;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment