Commit graph

3 commits

Author SHA1 Message Date
d34fb5bc63 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>
2026-09-19 14:42:30 +03:00
6043a67631 feat(render3d): give the moon a phase
The moon was fixed opposite the sun and worth a constant trickle of light. It
now carries a phase, 0 new .. 0.5 full .. 1 new again, and that one number
decides three things at once: the disc's terminator, the fraction of its light
that reaches the ground, and where in the sky it rides.

The moon is where the sun was `lag` of a day ago, so a full moon rises as the
sun sets and a new moon travels with the sun and is never seen. A new moon is
now a properly dark night, which is what makes a carried light worth having.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-10 16:15:19 +03:00
f25289db20 feat(gl): OpenGL 4.1 and the ludic.render3d renderer
Some checks failed
ci / build-and-test (push) Waiting to run
commit-lint / conventional-commits (push) Waiting to run
bootstrap / cfree-fixpoint (push) Has been cancelled
docs / build-and-deploy (push) Successful in 34s
`Gl.*` binds the whole OpenGL 4.1 core API — every entry point of the
platform gl3.h with every GL_* constant, generated by `ludic-dev glgen`
with per-call ABI thunks. Windowed builds get an NSOpenGLContext on the
existing window at Retina resolution; headless builds render into an
offscreen CGL context, so a program that uses Gl.* renders and
screenshots identically under the test harness. It links gl.ll, the
thunks and OpenGL.framework only when used; every other build stays
byte-identical.

packages/ludic.render3d is a physically based renderer written on that
surface: HDRI image-based lighting, GPU-generated terrain with scanned
PBR materials, CDLOD, cascaded shadows, glTF with skinning, instanced
vegetation with impostors, procedural grass, water, SSAO, and an HDR
pipeline with bloom, auto-exposure and ACES.

It also carries this session's work on it: the terrain at half its cost
(10.3 -> 5.4 ms of frame), the streaming hitch that got worse the longer
you played, a resize that emptied the world, and the packaging that lets
a game use the renderer from its own repository — `ludic assets`, the
material manifest shipping with the package, and shader lookup falling
back to the install root. See changes/ for each, with its numbers.

The camping game that drove all of it has moved out to its own
repository, Maroon Lake; examples/rendering/smooth.ludic stays as the
renderer's example here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-10 03:31:12 +03:00