summaryrefslogtreecommitdiff
path: root/src/3d
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-02 16:34:31 +0100
committerskal <pascal.massimino@gmail.com>2026-02-02 16:34:31 +0100
commitfcf1cbe0e520137d729152239c2aed68d9952cc5 (patch)
treeb9c3e46362bd68ee90744413cb8b7283da48b3e2 /src/3d
parent74cab8d6b91168a4681f1c9c19a8e32052d59e7b (diff)
fix(3d): Unify SDF path for all objects and stabilize shadows
- Converted floor in test_3d_render to a large SDF BOX for consistent shading. - Standardized lighting (light_dir = 1,1,1) and normal calculation for all objects. - Fixed calc_shadow bias and skip_idx to reliably prevent self-shadowing. - Improved raymarching robustness in fs_main to find exact SDF hit points.
Diffstat (limited to 'src/3d')
-rw-r--r--src/3d/renderer.cc56
1 files changed, 23 insertions, 33 deletions
diff --git a/src/3d/renderer.cc b/src/3d/renderer.cc
index 215cd97..9f43382 100644
--- a/src/3d/renderer.cc
+++ b/src/3d/renderer.cc
@@ -104,21 +104,16 @@ fn get_dist(p: vec3<f32>, obj_type: f32) -> f32 {
fn map_scene(p: vec3<f32>, skip_idx: u32) -> f32 {
var d = 1000.0;
let count = u32(globals.params.x);
-
for (var i = 0u; i < count; i = i + 1u) {
if (i == skip_idx) { continue; }
let obj = object_data.objects[i];
let obj_type = obj.params.x;
- // Skip rasterized objects (like the floor) in the SDF map
if (obj_type <= 0.0) { continue; }
-
let center = vec3<f32>(obj.model[3].x, obj.model[3].y, obj.model[3].z);
let scale = length(vec3<f32>(obj.model[0].x, obj.model[0].y, obj.model[0].z));
let mat3 = mat3x3<f32>(obj.model[0].xyz/scale, obj.model[1].xyz/scale, obj.model[2].xyz/scale);
let q = transpose(mat3) * (p - center) / scale;
-
- let dist = get_dist(q, obj_type) * scale;
- d = min(d, dist);
+ d = min(d, get_dist(q, obj_type) * scale);
}
return d;
}
@@ -128,11 +123,9 @@ fn calc_shadow(ro: vec3<f32>, rd: vec3<f32>, tmin: f32, tmax: f32, skip_idx: u32
var t = tmin;
for (var i = 0; i < 32; i = i + 1) {
let h = map_scene(ro + rd * t, skip_idx);
- if (h < 0.001) {
- return 0.0;
- }
- res = min(res, 32.0 * h / t); // Sharper shadow k=32
- t = t + h;
+ if (h < 0.001) { return 0.0; }
+ res = min(res, 16.0 * h / t); // Standard k=16
+ t = t + clamp(h, 0.01, 0.5);
if (t > tmax) { break; }
}
return clamp(res, 0.0, 1.0);
@@ -156,45 +149,42 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
var p: vec3<f32>;
var normal: vec3<f32>;
var base_color = in.color.rgb;
- // Slanted light for better shadow visibility
- let light_dir = normalize(vec3<f32>(0.5, 1.0, 0.5));
+ let light_dir = normalize(vec3<f32>(1.0, 1.0, 1.0));
- if (obj_type <= 0.0) { // Rasterized object
+ if (obj_type <= 0.0) { // Legacy raster path
p = in.world_pos;
let local_normal = normalize(cross(dpdx(in.local_pos), dpdy(in.local_pos)));
let mat3_it = mat3x3<f32>(obj.model_inv_tr[0].xyz, obj.model_inv_tr[1].xyz, obj.model_inv_tr[2].xyz);
normal = normalize(mat3_it * local_normal);
-
- let uv = p.xz * 0.1;
- let grid_val = textureSample(noise_tex, noise_sampler, uv).r;
- base_color = base_color * (0.4 + 0.6 * grid_val);
- } else { // SDF object
+ } else { // SDF path
let center = vec3<f32>(obj.model[3].x, obj.model[3].y, obj.model[3].z);
let scale = length(vec3<f32>(obj.model[0].x, obj.model[0].y, obj.model[0].z));
let ro = globals.camera_pos_time.xyz;
let rd = normalize(in.world_pos - ro);
- var t_hit = length(in.world_pos - ro);
- p = ro + rd * t_hit;
- let mat3 = mat3x3<f32>(obj.model[0].xyz/scale, obj.model[1].xyz/scale, obj.model[2].xyz/scale);
-
- var hit = false;
- for (var i = 0; i < 40; i = i + 1) {
+ // Raymarch from camera to find exact SDF hit
+ var t = length(in.world_pos - ro) * 0.9; // Start slightly before the proxy hull
+ for (var i = 0; i < 64; i = i + 1) {
+ p = ro + rd * t;
+ let mat3 = mat3x3<f32>(obj.model[0].xyz/scale, obj.model[1].xyz/scale, obj.model[2].xyz/scale);
let q = transpose(mat3) * (p - center) / scale;
- let d_world = get_dist(q, obj_type) * scale;
- if (d_world < 0.001) { hit = true; break; }
- if (d_world > 3.0 * scale) { break; }
- p = p + rd * d_world;
+ let d = get_dist(q, obj_type) * scale;
+ if (d < 0.001) { break; }
+ t = t + d;
+ if (t > length(in.world_pos - ro) * 1.5) { discard; }
}
- if (!hit) { discard; }
-
+ let mat3 = mat3x3<f32>(obj.model[0].xyz/scale, obj.model[1].xyz/scale, obj.model[2].xyz/scale);
let q_hit = transpose(mat3) * (p - center) / scale;
normal = normalize(mat3 * get_normal(q_hit, obj_type));
}
- let shadow = calc_shadow(p + normal * 0.02, light_dir, 0.02, 20.0, in.instance_index);
- let lighting = (max(dot(normal, light_dir), 0.0) * shadow) + 0.1;
+ // Shadow ray: start from surface, march towards light
+ // Use instance skipping to avoid self-shadowing artifacts
+ let shadow = calc_shadow(p, light_dir, 0.05, 20.0, in.instance_index);
+
+ let diffuse = max(dot(normal, light_dir), 0.0);
+ let lighting = diffuse * (0.1 + 0.9 * shadow) + 0.1; // Ambient + Shadowed Diffuse
return vec4<f32>(base_color * lighting, 1.0);
}