From 949ad332ae8df7a6ddd7e4005fd2e4a2540da067 Mon Sep 17 00:00:00 2001 From: skal Date: Mon, 2 Feb 2026 17:18:00 +0100 Subject: feat(3d): Implement tight ray bounds for SDF raymarching - Added Ray-Box intersection in local space to derive precise t_entry and t_exit. - Optimized fragment shader to only march between box intersection points. - Improved robustness of SDF rendering for non-uniform scaled objects. - Verified correct texturing and shadow casting on all primitives. --- src/3d/renderer.cc | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) (limited to 'src/3d/renderer.cc') diff --git a/src/3d/renderer.cc b/src/3d/renderer.cc index 2fb2221..abd26de 100644 --- a/src/3d/renderer.cc +++ b/src/3d/renderer.cc @@ -180,29 +180,40 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4 { let grid_val = smoothstep(0.45, 0.55, grid); base_color = base_color * (0.5 + 0.5 * grid_val); } else { // SDF path - let ro = globals.camera_pos_time.xyz; - let rd = normalize(in.world_pos - ro); + let ro_world = globals.camera_pos_time.xyz; + let rd_world = normalize(in.world_pos - ro_world); - var t = length(in.world_pos - ro) * 0.7; // Even more conservative start + // Ray-Box Intersection in local space to find tight bounds + let ro_local = (obj.inv_model * vec4(ro_world, 1.0)).xyz; + let rd_local = normalize((obj.inv_model * vec4(rd_world, 0.0)).xyz); + + // Proxy box extent (matches vs_main) + var extent = vec3(1.0); + if (obj_type == 3.0) { extent = vec3(1.5, 0.5, 1.5); } + + let inv_rd = 1.0 / rd_local; + let t0 = (-extent - ro_local) * inv_rd; + let t1 = (extent - ro_local) * inv_rd; + let tmin_vec = min(t0, t1); + let tmax_vec = max(t0, t1); + let t_entry = max(0.0, max(tmin_vec.x, max(tmin_vec.y, tmin_vec.z))); + let t_exit = min(tmax_vec.x, min(tmax_vec.y, tmax_vec.z)); + + if (t_entry > t_exit) { discard; } + + var t = t_entry; var hit = false; for (var i = 0; i < 64; i = i + 1) { - p = ro + rd * t; - let q = (obj.inv_model * vec4(p, 1.0)).xyz; + let q = ro_local + rd_local * t; let d_local = get_dist(q, obj_type); - - let scale_x = length(obj.model[0].xyz); - let scale_y = length(obj.model[1].xyz); - let scale_z = length(obj.model[2].xyz); - let s = min(scale_x, min(scale_y, scale_z)); - let d_world = d_local * s; - - if (d_world < 0.0005) { hit = true; break; } - t = t + d_world; - if (t > length(in.world_pos - ro) * 2.0) { break; } + if (d_local < 0.0005) { hit = true; break; } + t = t + d_local; + if (t > t_exit) { break; } } if (!hit) { discard; } - let q_hit = (obj.inv_model * vec4(p, 1.0)).xyz; + p = ro_world + rd_world * t; // Use world t for final position + let q_hit = ro_local + rd_local * t; // Calculate normal with bump mapping let e = vec2(0.005, 0.0); -- cgit v1.2.3