From 39167ee05fea7e632b83e050944236a8bdc34fec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Bousqui=C3=A9?= Date: Sat, 19 Sep 2026 12:05:57 +0200 Subject: [PATCH] fix(shadow): correct comparison sampler from GreaterEqual to LessEqual MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the shadow map cleared to 1.0 (farthest depth from light) and the shadow pass writing smaller depths for surfaces closer to the light, the fragment-to-light distance must be <= the stored surface depth for lit pixels. GreaterEqual was inverted — everything appeared lit with no shadows rendered. --- lib/src/core/renderer.rs | 7 ++++--- lib/src/shaders/standard_shader.wgsl | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/src/core/renderer.rs b/lib/src/core/renderer.rs index d063ff7..1d2181d 100644 --- a/lib/src/core/renderer.rs +++ b/lib/src/core/renderer.rs @@ -162,9 +162,10 @@ impl Renderer { min_filter: wgpu::FilterMode::Linear, mipmap_filter: wgpu::MipmapFilterMode::Nearest, // Comparison sampler : `textureSampleCompare` returns 1 when the sampled depth passes - // this test against the reference, 0 otherwise (D5). GreaterEqual = lit when nothing - // closer than the fragment has been written into the shadow map. - compare: Some(wgpu::CompareFunction::GreaterEqual), + // this test against the reference, 0 otherwise (D5). LessEqual = lit when the fragment + // is no farther from the light than the surface recorded in the shadow map (the map is + // cleared to 1.0 = far, so open un-blocked texels pass and surfaces behind a blocker fail). + compare: Some(wgpu::CompareFunction::LessEqual), ..Default::default() }); let shadow_map_layout = create_shadow_map_bind_group_layout(&device); diff --git a/lib/src/shaders/standard_shader.wgsl b/lib/src/shaders/standard_shader.wgsl index e251096..24c2625 100644 --- a/lib/src/shaders/standard_shader.wgsl +++ b/lib/src/shaders/standard_shader.wgsl @@ -207,7 +207,7 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4 { // Étape 14 (DRAFT 3.2, D5) : PCF shadow factor for this fragment. Reprojects the world position // into the shadow light's clip space, converts to depth-map UVs + normalized depth, then averages -// a 3×3 `textureSampleCompare` neighborhood using the comparison sampler (GreaterEqual). Returns +// a 3×3 `textureSampleCompare` neighborhood using the comparison sampler (LessEqual). Returns // 1.0 when fully lit (or shadows disabled), 0.0 when fully in shadow. The reference depth is // pulled toward the viewer by `frame.shadow_params.y` (bias) to suppress acne. fn compute_shadow(world_pos: vec3) -> f32 {