GL fog: per-fragment factor -- terrain/cloud no longer escape the fog

Fog was computed per VERTEX; vertices behind the eye clamped to factor
zero, and the terrain/cloud triangles are large enough to span the
camera, so interpolation dragged the whole ground to unfogged (bright
terrain through the pre-drop blackout and the respawn reveal). The
eye-space depth now rides the varying (perspective-correct) and the
factor is computed per fragment, where clipping guarantees valid depth.

Verified offline: pre-drop hold renders solid black + HUD only (matches
the period screenshot exactly); the respawn fade shows the authentic
near-first reveal from the operator's VHS (ground clear, fog wall at
distance, sky still white).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-08 20:32:38 -05:00
co-authored by Claude Fable 5
parent bb8978c127
commit c13613e259
+13 -4
View File
@@ -84,9 +84,12 @@ void main() {
if (u_has_col == 1) base *= in_col; // vertex colors modulate
v_base = clamp(base, 0.0, 1.0);
v_uv = in_uv;
v_fog = (u_fog_on == 1)
? clamp((z - u_fogrange.x) / (u_fogrange.y - u_fogrange.x), 0.0, 1.0)
: 0.0;
// fog factor moves to the FRAGMENT shader: computing it per vertex
// zeroed it on vertices BEHIND the eye, and the terrain/cloud triangles
// are huge enough to span the camera -- interpolation dragged the whole
// ground to "unfogged" (the pre-drop blackout leak). The eye depth
// itself interpolates perspective-correct, so pass that instead.
v_fog = z;
}
"""
@@ -98,6 +101,8 @@ uniform int u_alpha_cut;
uniform vec2 u_uvoff; // board-side SCROLL
uniform float u_opacity; // DITHER n -> screen-door
uniform vec3 u_fogcol;
uniform int u_fog_on;
uniform vec2 u_fogrange; // near, far
in vec3 v_base;
in vec2 v_uv;
in float v_fog;
@@ -120,7 +125,11 @@ void main() {
}
// alpha only takes effect in the deferred blended pass (opaque pass
// renders with BLEND disabled)
f_color = vec4(mix(rgb, u_fogcol, v_fog), clamp(v_alpha, 0.0, 1.0));
float fogf = (u_fog_on == 1)
? clamp((v_fog - u_fogrange.x) / (u_fogrange.y - u_fogrange.x),
0.0, 1.0)
: 0.0;
f_color = vec4(mix(rgb, u_fogcol, fogf), clamp(v_alpha, 0.0, 1.0));
}
"""