diff --git a/crates/benilla-world/src/shaders/static_gx.wgsl b/crates/benilla-world/src/shaders/static_gx.wgsl index fb968169..859018e9 100644 --- a/crates/benilla-world/src/shaders/static_gx.wgsl +++ b/crates/benilla-world/src/shaders/static_gx.wgsl @@ -1264,10 +1264,28 @@ struct GxVsOut { @builtin(position) position: vec4, @location(0) world_position: vec4, @location(1) world_normal: vec3, - @location(2) uv: vec2, + // CENTROID, and this is load-bearing under MSAA. A partially covered pixel is shaded ONCE, at + // the pixel centre — and at a geometry edge that centre can lie OUTSIDE the triangle, so a + // centre-interpolated varying is EXTRAPOLATED past its vertices. For a UV into this lane's + // shared pool that lands on unrelated texels, and the fragment comes back a saturated colour + // that exists nowhere near it: single bright pixels strung along every seam, which is what + // `gxMultisample 8` used to paint across interior walls. Centroid moves the sample point back + // inside the covered area, so the UV is interpolated and never extrapolated. + // + // Measured on `daylight-if-forge`: six such pixels at 8x — (255,255,255), (37,35,255), + // (204,26,33) against a (26,32,45) background — and none with this. The entity path does not + // show it, which is why the fix is here and not in `wow_model.wgsl`. + @location(2) @interpolate(perspective, centroid) uv: vec2, @location(3) @interpolate(flat) word: u32, - @location(4) point_lit: vec3, - @location(5) color: vec4, + // CENTROID, for the reason the UV above carries it — and this is the one that was actually + // painting the seams. `point_lit` is a SUM OF POINT LIGHTS accumulated per vertex, so + // extrapolating it past the triangle does not shift a texel, it runs the sum away: the + // fragment comes back the saturated colour of whatever light dominates that vertex. The six + // stray pixels measured on `daylight-if-forge` were (255,255,255), (255,133,95), (36,34,255), + // (255,145,51), (255,52,40) and (190,26,33) — white, orange, blue, orange, red and red, which + // is the Great Forge's own lighting read off a cliff, not texture garbage. + @location(4) @interpolate(perspective, centroid) point_lit: vec3, + @location(5) @interpolate(perspective, centroid) color: vec4, // MONKEY (outdoor torch shadows; ext light k8): WHICH ≤`EXT_SEL_K` exterior table entries // `point_lit` was summed from, packed 8 bits each across FOUR u32s (see `EXT_SEL_NONE` / // `ext_sel_get`). FLAT, because it is a choice, not a quantity — interpolating packed indices