fix: spot — corrige le signe du test de cône (cube noir)

Le test du cône comparait l (surface->lumière) à dir_angle.xyz (lumière->scène),
deux directions opposées, donc cone ≈ -1 et facteur spot = 0 : les spots
n'éclairaient rien (cube noir). On teste désormais -l (lumière->point), aligné
avec l'axe du cône. Ajout d'un test Rust qui verrouille l'invariant (alignement
+1 sur l'axe). Build/test/WGSL/fmt OK.
This commit is contained in:
Jérôme Bousquié
2026-09-18 20:48:20 +02:00
parent 73085de537
commit 2582b6f571
2 changed files with 33 additions and 4 deletions
+8 -4
View File
@@ -169,15 +169,19 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
}
// Lumières spot (indices num_directional + num_point..num_directional + num_point +
// num_spot). Cône orienté : pénombre lissée entre le demi-angle intérieur (dir_angle.w) et
// un liseré extérieur (demi-angle − 0.1 rad), plus atténuation linéaire par rayon.
// num_spot). Cône orienté : on teste l'alignement de la direction **de la lumière vers le
// point** de la surface (-l, car l pointe de la surface vers la lumière) avec l'axe du cône
// (dir_angle.xyz, de la lumière vers la scène). Pénombre lissée entre le demi-angle intérieur
// (dir_angle.w) et un liseré extérieur (demi-angle − 0.1 rad), plus atténuation linéaire.
let spot_base = frame.num_directional + frame.num_point;
for (var i = spot_base; i < spot_base + frame.num_spot; i++) {
let to_light = frame.lights[i].position_dir.xyz - in.world_pos;
let dist = length(to_light);
let l = to_light / max(dist, 1e-4);
let l = to_light / max(dist, 1e-4); // surface -> lumière
let ndotl = max(dot(n, l), 0.0);
let cone = dot(l, normalize(frame.lights[i].dir_angle.xyz));
// direction lumière -> point de la surface = -l ; alignée avec l'axe du cône (dir_angle.xyz).
let to_point = -l;
let cone = dot(to_point, normalize(frame.lights[i].dir_angle.xyz));
let cos_inner = frame.lights[i].dir_angle.w;
let cos_outer = cos_inner - 0.1;
let spot_factor = clamp((cone - cos_outer) / max(cos_inner - cos_outer, 1e-4), 0.0, 1.0);