summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-02 13:45:07 +0100
committerskal <pascal.massimino@gmail.com>2026-02-02 13:45:07 +0100
commitfc4c3a907ebe73169d9b869bc9d559645a23cbe9 (patch)
tree80f357f9479d31d00017ab8a669991cbea5ac66b
parent90f55a5dcb115cc6489cf8b25fe23fe71071a559 (diff)
feat(3d): Unify shadow calculations in shader
- Refactored the fragment shader to calculate raymarched shadows for all fragments, not just SDF objects. - This enables rasterized objects (like the floor) to receive shadows from SDF objects, fixing the missing shadows in the test scene. - This serves as a proof-of-concept for a unified lighting pipeline.
-rw-r--r--src/3d/renderer.cc146
1 files changed, 70 insertions, 76 deletions
diff --git a/src/3d/renderer.cc b/src/3d/renderer.cc
index 031895d..267c165 100644
--- a/src/3d/renderer.cc
+++ b/src/3d/renderer.cc
@@ -148,86 +148,80 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
let obj = object_data.objects[in.instance_index];
let obj_type = obj.params.x;
- if (obj_type == 0.0) {
- let d = abs(in.local_pos);
- let edge_dist = max(max(d.x, d.y), d.z);
- var col = in.color.rgb;
- if (edge_dist > 0.95) {
- col = vec3<f32>(1.0, 1.0, 1.0);
- } else {
- let normal = normalize(cross(dpdx(in.local_pos), dpdy(in.local_pos)));
- let light = normalize(vec3<f32>(0.5, 1.0, 0.5));
- let diff = max(dot(normal, light), 0.2);
- col = col * diff;
+ var p: vec3<f32>;
+ var normal: vec3<f32>;
+ let light_dir = normalize(vec3<f32>(1.0, 1.0, 1.0));
+
+ if (obj_type == 0.0) { // Rasterized object (like the floor)
+ p = in.world_pos;
+ let local_normal = normalize(cross(dpdx(in.local_pos), dpdy(in.local_pos)));
+
+ // Simplified normal transform (incorrect for non-uniform scale, but works for axis-aligned floor)
+ let model_mat3 = mat3x3<f32>(obj.model[0].xyz, obj.model[1].xyz, obj.model[2].xyz);
+ normal = normalize(model_mat3 * local_normal);
+ } else { // SDF object
+ 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 = length(in.world_pos - ro);
+ p = ro + rd * t;
+
+ 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) {
+ 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;
}
- return vec4<f32>(col, 1.0);
- }
-
- 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 = length(in.world_pos - ro);
- var p = ro + rd * t;
-
- 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++) {
- 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;
+
+ if (!hit) { discard; }
+
+ let q_hit = transpose(mat3) * (p - center) / scale;
+
+ let e = vec2<f32>(0.005, 0.0);
+ let disp_strength = 0.05;
+
+ // Calculate normal with bump mapping
+ let q_x1 = q_hit + e.xyy;
+ let uv_x1 = vec2<f32>(atan2(q_x1.x, q_x1.z) / 6.28 + 0.5, acos(clamp(q_x1.y / length(q_x1), -1.0, 1.0)) / 3.14);
+ let h_x1 = textureSample(noise_tex, noise_sampler, uv_x1).r;
+ let d_x1 = get_dist(q_x1, obj_type) - disp_strength * h_x1;
+
+ let q_x2 = q_hit - e.xyy;
+ let uv_x2 = vec2<f32>(atan2(q_x2.x, q_x2.z) / 6.28 + 0.5, acos(clamp(q_x2.y / length(q_x2), -1.0, 1.0)) / 3.14);
+ let h_x2 = textureSample(noise_tex, noise_sampler, uv_x2).r;
+ let d_x2 = get_dist(q_x2, obj_type) - disp_strength * h_x2;
+
+ let q_y1 = q_hit + e.yxy;
+ let uv_y1 = vec2<f32>(atan2(q_y1.x, q_y1.z) / 6.28 + 0.5, acos(clamp(q_y1.y / length(q_y1), -1.0, 1.0)) / 3.14);
+ let h_y1 = textureSample(noise_tex, noise_sampler, uv_y1).r;
+ let d_y1 = get_dist(q_y1, obj_type) - disp_strength * h_y1;
+
+ let q_y2 = q_hit - e.yxy;
+ let uv_y2 = vec2<f32>(atan2(q_y2.x, q_y2.z) / 6.28 + 0.5, acos(clamp(q_y2.y / length(q_y2), -1.0, 1.0)) / 3.14);
+ let h_y2 = textureSample(noise_tex, noise_sampler, uv_y2).r;
+ let d_y2 = get_dist(q_y2, obj_type) - disp_strength * h_y2;
+
+ let q_z1 = q_hit + e.yyx;
+ let uv_z1 = vec2<f32>(atan2(q_z1.x, q_z1.z) / 6.28 + 0.5, acos(clamp(q_z1.y / length(q_z1), -1.0, 1.0)) / 3.14);
+ let h_z1 = textureSample(noise_tex, noise_sampler, uv_z1).r;
+ let d_z1 = get_dist(q_z1, obj_type) - disp_strength * h_z1;
+
+ let q_z2 = q_hit - e.yyx;
+ let uv_z2 = vec2<f32>(atan2(q_z2.x, q_z2.z) / 6.28 + 0.5, acos(clamp(q_z2.y / length(q_z2), -1.0, 1.0)) / 3.14);
+ let h_z2 = textureSample(noise_tex, noise_sampler, uv_z2).r;
+ let d_z2 = get_dist(q_z2, obj_type) - disp_strength * h_z2;
+
+ let n_local = normalize(vec3<f32>(d_x1 - d_x2, d_y1 - d_y2, d_z1 - d_z2));
+
+ normal = normalize(mat3 * n_local);
}
-
- if (!hit) { discard; }
-
- // Shading
- let q_hit = transpose(mat3) * (p - center) / scale;
-
- // Calculate normal with bump mapping
- let e = vec2<f32>(0.005, 0.0);
- let disp_strength = 0.05;
-
- let q_x1 = q_hit + e.xyy;
- let uv_x1 = vec2<f32>(atan2(q_x1.x, q_x1.z) / 6.28 + 0.5, acos(clamp(q_x1.y / length(q_x1), -1.0, 1.0)) / 3.14);
- let h_x1 = textureSample(noise_tex, noise_sampler, uv_x1).r;
- let d_x1 = get_dist(q_x1, obj_type) - disp_strength * h_x1;
-
- let q_x2 = q_hit - e.xyy;
- let uv_x2 = vec2<f32>(atan2(q_x2.x, q_x2.z) / 6.28 + 0.5, acos(clamp(q_x2.y / length(q_x2), -1.0, 1.0)) / 3.14);
- let h_x2 = textureSample(noise_tex, noise_sampler, uv_x2).r;
- let d_x2 = get_dist(q_x2, obj_type) - disp_strength * h_x2;
-
- let q_y1 = q_hit + e.yxy;
- let uv_y1 = vec2<f32>(atan2(q_y1.x, q_y1.z) / 6.28 + 0.5, acos(clamp(q_y1.y / length(q_y1), -1.0, 1.0)) / 3.14);
- let h_y1 = textureSample(noise_tex, noise_sampler, uv_y1).r;
- let d_y1 = get_dist(q_y1, obj_type) - disp_strength * h_y1;
-
- let q_y2 = q_hit - e.yxy;
- let uv_y2 = vec2<f32>(atan2(q_y2.x, q_y2.z) / 6.28 + 0.5, acos(clamp(q_y2.y / length(q_y2), -1.0, 1.0)) / 3.14);
- let h_y2 = textureSample(noise_tex, noise_sampler, uv_y2).r;
- let d_y2 = get_dist(q_y2, obj_type) - disp_strength * h_y2;
-
- let q_z1 = q_hit + e.yyx;
- let uv_z1 = vec2<f32>(atan2(q_z1.x, q_z1.z) / 6.28 + 0.5, acos(clamp(q_z1.y / length(q_z1), -1.0, 1.0)) / 3.14);
- let h_z1 = textureSample(noise_tex, noise_sampler, uv_z1).r;
- let d_z1 = get_dist(q_z1, obj_type) - disp_strength * h_z1;
-
- let q_z2 = q_hit - e.yyx;
- let uv_z2 = vec2<f32>(atan2(q_z2.x, q_z2.z) / 6.28 + 0.5, acos(clamp(q_z2.y / length(q_z2), -1.0, 1.0)) / 3.14);
- let h_z2 = textureSample(noise_tex, noise_sampler, uv_z2).r;
- let d_z2 = get_dist(q_z2, obj_type) - disp_strength * h_z2;
-
- let n_local = normalize(vec3<f32>(d_x1 - d_x2, d_y1 - d_y2, d_z1 - d_z2));
-
- let n_world = mat3 * n_local;
- let normal = normalize(n_world);
- let light_dir = normalize(vec3<f32>(1.0, 1.0, 1.0));
let shadow = calc_shadow(p + normal * 0.05, light_dir, 0.0, 20.0);
-
let lighting = (max(dot(normal, light_dir), 0.0) * shadow) + 0.1;
return vec4<f32>(in.color.rgb * lighting, 1.0);
}