diff options
| author | skal <pascal.massimino@gmail.com> | 2026-02-02 13:45:07 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-02-02 13:45:07 +0100 |
| commit | fc4c3a907ebe73169d9b869bc9d559645a23cbe9 (patch) | |
| tree | 80f357f9479d31d00017ab8a669991cbea5ac66b /src/3d | |
| parent | 90f55a5dcb115cc6489cf8b25fe23fe71071a559 (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.
Diffstat (limited to 'src/3d')
| -rw-r--r-- | src/3d/renderer.cc | 146 |
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); } |
