render3d: r3d_fog_wall(dist) - fog that closes to the sky's horizon colour from 0.3 dist to dist, and nothing drawn past dist + 8 m

Every lit program blends toward the horizon colour (the prefiltered sky with the sun's inscatter,
so it carries the day's grade); the sky's horizon band is pulled to the same colour, wider the
closer the wall. The far plane, scatter and stream cull reach and the shadow cascades are clamped
to the wall; the reflection pass shares the shaders and the cull. 0 is off: every branch is gated
on u_fog_wall > 0 and r3d_reach hands back the far it was given. R3D_FOG_WALL=<m> for a shot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-29 15:07:40 +03:00
parent 160ce96e4f
commit b9f9cb8495
67 changed files with 335 additions and 227 deletions

View file

@ -142,17 +142,22 @@ function shadow_pass(render3d_st: mut Render3dState) -> void {
gpu_depth_func(render3d_st, GL_LESS)
gpu_depth_bias(render3d_st, 2.0, 4.0)
gpu_cull(render3d_st, false)
# a fog wall: a cascade reaches no further than it, and one that begins past it is only cleared
let wall = r3d_reach(render3d_st, 0.0)
for c in 0 .. SHADOW_CASCADES {
render3d_st.sh_cascade = c
shadow_fit(render3d_st, c, near, render3d_st.sh_split[c])
var far = render3d_st.sh_split[c]
if wall > 0.0 and far > wall { far = Math.max(wall, near + 1.0) }
shadow_fit(render3d_st, c, near, far)
prof_cpu_mark(render3d_st, "shadow fit")
let past = wall > 0.0 and near >= wall
near = render3d_st.sh_split[c]
gpu_fb_depth_layer(render3d_st, render3d_st.sh_tex, c)
if render3d_st.r3d_debug and c == 0 { shadow_debug_fbo(render3d_st) }
gpu_clear(render3d_st, GL_DEPTH_BUFFER_BIT)
let vp = shadow_cascade_vp(render3d_st, c)
# shadows off (a video setting): the cascades stay cleared, so everything reads lit
if render3d_st.sh_enabled {
if render3d_st.sh_enabled and not past {
if not render3d_st.sh_skip_terrain { terrain_draw_shadow(vp) }
r3d_scene_casters(render3d_st, vp)
}