feat(render3d): the air and the light are the hour's, not one constant apiece

Aerial perspective is a curve now. A low sun shines through far more air than a
high one and shines ALONG the ground rather than down onto it, so density, height
falloff and forward scatter all ride the sun's elevation; overcast thickens the air
and flattens the scatter, because a grey sky has no disc to scatter from. `lowsun`
falls away BELOW the horizon as well as above it, or the middle of the night gets a
dawn's haze with no dawn to justify it.

The term that was missing entirely is distance DESATURATION. Blending a saturated
green ridge toward a saturated blue noon sky leaves a saturated ridge - which is why
the same valley read as a photograph at dusk, where the fog colour happened to be a
warm grey, and as a toy at one o'clock. A surface is now pulled toward its own
luminance faster than the fog itself arrives. Measured far/near saturation at the
camp: 07:00 1.11 -> 0.89, 09:00 1.04 -> 0.93, 13:00 0.98 -> 0.89.

The grade is the hour's too - nine literals bound at the draw, written by
daylight_set now. Noon is the case worth naming: direct sun is warm-white and the
only thing filling a midday shadow is a blue sky, so noon gets a cool balance over a
blue-lifted shadow with hard contrast, and dawn and dusk the reverse. Ground R-B,
lit vs shadowed: 07:00 +42.8/+14.2 -> +48.9/+15.1, 13:00 +32.2/+14.8 -> +25.2/+2.9.
Gain is left alone deliberately: the grade is `c * gain + lift * (1 - c)`, so warming
it warms the whole frame, and warming it at noon made one o'clock yellower than seven
in the morning - the opposite of the point.

The visible sky is relit. Turning a photograph on its axis does not change what
colour it was taken at, so every sunset had a mid-morning blue overhead. An analytic
sky supplies the chroma and the photograph keeps the luminance: the cloud stays where
it is and goes orange at dusk, the zenith goes deep blue at noon, and no second sky
is shipped. It fades out under the horizon and eases off under cloud.

The ground bounce follows the ground, crossing meadow to rock at the map's treeline
instead of being one green constant everywhere including above the scree.

R3D_NOAIR=1 restores all of it, so a before-and-after comes from one binary at one
hour; it joins R3D_NOCLOUD / R3D_NOSHADOW / R3D_NOGI.

Verified on macOS OpenGL, macOS Vulkan (MoltenVK) and Windows Vulkan (RTX 3070 Ti).
Backends agree: mean difference 0.15-0.88/255 within a machine. Across machines the
ORIGINAL renderer already differed by 5.02/255 at 19:12 and this build differs by
2.80, so cross-platform variance is pre-existing and did not grow. 400 frames: GL
7.4 s before and after, VK 7.0 s before and after.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-19 14:42:30 +03:00
parent f094acfdb5
commit d34fb5bc63
59 changed files with 1560 additions and 1035 deletions

View file

@ -0,0 +1,35 @@
bump: minor
type: feat
The air and the light are the hour's, not one constant apiece.
Aerial perspective is a curve now. A low sun shines through far more air than a high
one and shines ALONG the ground rather than down onto it, so density, height falloff
and forward scatter all ride the sun's own elevation, and overcast thickens the air
while flattening the scatter. The term that was missing entirely is distance
DESATURATION: a surface is pulled toward its own luminance faster than the fog itself
arrives. Without it, blending a saturated ridge toward a saturated blue noon sky left
a saturated ridge, and a midday frame had a mountain three kilometres off reading as
vividly as a bench two metres from the camera.
The grade is the hour's too. White balance, the shadows' floor, contrast and
saturation were nine literals bound at the draw; daylight.ludic writes them now.
Noon is the case worth naming: direct sun is warm-white and the only thing filling a
midday shadow is a blue sky, so noon gets a cool balance over a blue-lifted shadow
with hard contrast between it and the lit ground, and dawn and dusk get the reverse.
Gain is deliberately left alone - the grade is `c * gain + lift * (1 - c)`, so it
warms the whole frame rather than the highlights.
The visible sky is relit. It is one HDRI turned on its axis so its sun sits where the
hour wants it, and turning a photograph does not change what colour it was taken at -
so a sunset had a mid-morning blue overhead. An analytic sky supplies the chroma while
the photograph keeps the luminance, so the cloud stays where it is and goes orange at
dusk, and the zenith goes deep blue at noon, with no second sky shipped. It fades out
under the horizon, where the night's own tint, stars and moon take over, and eases off
under heavy cloud.
And the ground bounce follows the ground: the colour a surface is filled with from
below is the map's now, crossing from meadow to rock at its treeline, instead of one
green constant everywhere including above the scree.
R3D_NOAIR=1 restores all of it to what it was, so a before-and-after comes from one
binary at one hour. Measured at 400 frames: no cost on either backend.