diff options
| author | skal <pascal.massimino@gmail.com> | 2026-02-02 17:18:00 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-02-02 17:18:00 +0100 |
| commit | 949ad332ae8df7a6ddd7e4005fd2e4a2540da067 (patch) | |
| tree | 7e93b62a8a7146c5c80f9f03c968095469132eee | |
| parent | 01b3442ceb51983b2df920259d13edf933a6bfe3 (diff) | |
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.
| -rw-r--r-- | src/3d/renderer.cc | 43 |
1 files changed, 27 insertions, 16 deletions
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<f32> { 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<f32>(ro_world, 1.0)).xyz; + let rd_local = normalize((obj.inv_model * vec4<f32>(rd_world, 0.0)).xyz); + + // Proxy box extent (matches vs_main) + var extent = vec3<f32>(1.0); + if (obj_type == 3.0) { extent = vec3<f32>(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<f32>(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<f32>(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<f32>(0.005, 0.0); |
