Created
December 19, 2019 12:22
-
-
Save dwilliamson/681204e4e0d528925841ca8143609e55 to your computer and use it in GitHub Desktop.
March To Surface
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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