From 177d7c63791214f4c90c5f68d3de60f4f448e1ca Mon Sep 17 00:00:00 2001 From: shadow cat Date: Sat, 14 Sep 2024 21:35:20 -0400 Subject: [PATCH] pop stack using highest differing bit --- src/client/render/voxel/ray_oct/compute.wgsl | 94 ++++++++++++-------- 1 file changed, 55 insertions(+), 39 deletions(-) diff --git a/src/client/render/voxel/ray_oct/compute.wgsl b/src/client/render/voxel/ray_oct/compute.wgsl index dfccc15..5d2f60e 100644 --- a/src/client/render/voxel/ray_oct/compute.wgsl +++ b/src/client/render/voxel/ray_oct/compute.wgsl @@ -57,6 +57,7 @@ const ZERO3F = vec3(0.0); const ZERO2F = vec2(0.0); const FULL_ALPHA = 0.999; const EPSILON = 0.00000000001; +const MAX_ITERS = 1000; fn trace_full(pos_view: vec4, dir_view: vec4) -> vec4 { let gi = 0; @@ -85,7 +86,7 @@ fn trace_full(pos_view: vec4, dir_view: vec4) -> vec4 { (group.transform * vec4(0.0, dir_if.y, 0.0, 0.0)).xyz, (group.transform * vec4(0.0, 0.0, dir_if.z, 0.0)).xyz, ); - var next_normal = vec3(0.0, 0.0, 0.0); + var axis = 0u; // find where ray intersects with group let pos_min = (vec3(1.0) - dir_uf) * dim_f; @@ -94,7 +95,6 @@ fn trace_full(pos_view: vec4, dir_view: vec4) -> vec4 { // time of intersection; x = td + p, solve for t let t_min = (pos_min - pos) / dir; let t_max = (pos_max - pos) / dir; - var t = 0.0; if outside3f(pos, ZERO3F, dim_f) { // points of intersection let px = pos + t_min.x * dir; @@ -111,11 +111,12 @@ fn trace_full(pos_view: vec4, dir_view: vec4) -> vec4 { return vec4(0.0); } pos = select(select(pz, py, hit.y), px, hit.x); - t = select(select(t_min.z, t_min.y, hit.y), t_min.x, hit.x); - next_normal = select(select(normals[2], normals[1], hit.y), normals[0], hit.x); + axis = select(select(2u, 1u, hit.y), 0u, hit.x); } - var vox_pos = clamp(vec3(pos), vec3(0), dim_i - vec3(1)); + // time to move 1 unit in each direction let inc_t = abs(1.0 / dir); + let t_offset = max(max(t_min.x, t_min.y), t_min.z); + var t = max(0.0, t_offset); let dir_i = vec3(dir_if); let dir_u = vec3((dir_i + vec3(1)) / 2); @@ -123,70 +124,85 @@ fn trace_full(pos_view: vec4, dir_view: vec4) -> vec4 { let inv_dir_bits = 7 - dir_bits; var node_start = 1u; - var t_center = (t_max + t_min) / 2.0; - var half_t_span = f32(256 / 2) * inc_t; - var scale = 0; - - var dir_idx = vec3(vec3(t) > t_center); - var child = vec_to_dir(dir_idx); - var parents = array(); + var scale = 7u; + var half_t_span = f32(1u << scale) * inc_t; + var t_center = t_min + half_t_span; var color = vec4(0.0); + var parents = array(); - for (var safety = 0; safety < 1000; safety += 1) { + var child = (u32(t > t_center.x) << 2) + (u32(t > t_center.y) << 1) + u32(t > t_center.z); + var child_pos = dir_to_vec(child); + var vox_pos = child_pos * (1u << scale); + + var iters = 0; + loop { + if iters == MAX_ITERS { + return vec4(1.0, 0.0, 1.0, 1.0); + } + iters += 1; let node = voxels[group.offset + node_start + (child ^ inv_dir_bits)]; if node >= LEAF_BIT { let vcolor = get_color(node & LEAF_MASK); if vcolor.a > 0.0 { - let diffuse = max(dot(global_lights[0].dir, next_normal) + 0.1, 0.0); + let diffuse = max(dot(global_lights[0].dir, normals[axis]) + 0.1, 0.0); let ambient = 0.2; let lighting = max(diffuse, ambient); let new_color = min(vcolor.xyz * lighting, vec3(1.0)); color += vec4(new_color.xyz * vcolor.a, vcolor.a) * (1.0 - color.a); - if color.a > FULL_ALPHA { return color; } + if color.a > FULL_ALPHA { break; } } - let center_adj = t_center + half_t_span * vec3(dir_idx); - t = min(min(center_adj.x, center_adj.y), center_adj.z); - var move_dir = 0u; - if t == center_adj.x { move_dir = 4u; next_normal = normals[0]; } - if t == center_adj.y { move_dir = 2u; next_normal = normals[1]; } - if t == center_adj.z { move_dir = 1u; next_normal = normals[2]; } - if move_dir == 0 { return vec4(1.0); } - while (child & move_dir) > 0 { - if scale == 0 { return color; } + // move to next time point and determine which axis to move along + let t_next = t_center + half_t_span * vec3(child_pos); + t = min(min(t_next.x, t_next.y), t_next.z); + axis = select(select(0u, 1u, t == t_next.y), 2u, t == t_next.z); + let move_dir = 4u >> axis; - scale -= 1; + // check if need to pop stack + if (child & move_dir) > 0 { + // calculate new scale; first differing bit after adding + let new_pos = vox_pos[axis] + (1u << scale); + if new_pos == 256 { break; } + let differing = vox_pos[axis] ^ new_pos; + vox_pos[axis] = new_pos; + scale = firstLeadingBit(differing); + + // restore & recalculate parent let parent_info = parents[scale]; node_start = parent_info >> 3; child = parent_info & 7; - - dir_idx = dir_to_vec(child); - t_center -= half_t_span * (vec3(dir_idx * 2) - 1.0); - half_t_span *= 2.0; + let scale_vec = vec3(scale + 1); + vox_pos = (vox_pos >> scale_vec) << scale_vec; // remove lower scale bits + half_t_span = f32(1u << scale) * inc_t; + t_center = vec3(vox_pos) * inc_t + t_min + half_t_span; } - child = child ^ move_dir; - dir_idx = dir_to_vec(child); + // move to next child and voxel position + child ^= move_dir; + child_pos = dir_to_vec(child); + vox_pos |= child_pos << vec3(scale); } else { + // push current node to stack parents[scale] = (node_start << 3) + child; - scale += 1; + scale -= 1u; + // calculate child node vars half_t_span /= 2.0; - t_center += half_t_span * (vec3(dir_idx * 2) - 1.0); - dir_idx = vec3(vec3(t) > t_center); - - child = vec_to_dir(dir_idx); + t_center += half_t_span * (vec3(child_pos * 2) - 1.0); + child_pos = vec3(vec3(t) > t_center); + child = (child_pos.x << 2) + (child_pos.y << 1) + child_pos.z; + vox_pos += child_pos * (1u << scale); node_start = node_start + 8 + node; } } - return vec4(1.0, 0.0, 1.0, 1.0); + // return vec4(f32(iters) / f32(MAX_ITERS), 0.0, 0.0, 1.0); + return color; } const LEAF_BIT = 1u << 31u; const LEAF_MASK = ~LEAF_BIT; -// no clue if this is efficient, mod is faster for all I know fn dir_to_vec(bits: u32) -> vec3 { - return vec3(extractBits(bits, 2u, 1u), extractBits(bits, 1u, 1u), extractBits(bits, 0u, 1u)); + return vec3(bits >> 2, (bits & 2) >> 1, bits & 1); } fn vec_to_dir(vec: vec3) -> u32 {