Time-of-day sun driver + weather — design
The chosen design for animating the sky: a pure-CPU, deterministic DayCycle (facett-map3d-flight/src/daycycle.rs) that turns (latitude, day-of-year, hour, weather) into a facett_map3d::SunSky, driving the existing GPU PBR shader + CPU painter with no new passes (additive, L2). This is the single biggest realism win over a fixed SunSky::noon().
Pipeline (part-steps, each testable)
| # | step | fn | in → out | emit / bench |
| 1 | solar position | solar_angles(lat, doy, hour) |
time → SolarAngles{elevation, azimuth} |
daycycle.solar_angles bench; asserted (east/noon/west, season) |
| 2 | sun direction | sun_dir(angles) |
angles → unit surface→sun (+X east,+Y up,+Z north), unclamped so night stays below the horizon | daycycle.sun_dir bench |
| 3 | direct-sun colour | sun_sky |
sun_color = base ⊙ T(alt, μ_sun) from the reused atmos transmittance LUT, hue-normalised |
golden-hour reddening asserted |
| 4 | sun intensity | daylight_curve(elev) |
0 below −6°, rising with sin(elev) to a noon peak |
night/golden dimming asserted |
| 5 | sky tint + ambient | atmos.sky_colors × sky_scale |
zenith/horizon tint, dimmed by a twilight/night gate | daycycle.sun_sky bench |
| 6 | weather blend | Weather.cloudiness |
overcast: dim sun, grey+desaturate sky, lift ambient, flatten | overcast asserted (monotone) |
Key decisions
- Golden hour from physics, not paint (L5 reuse). The direct sunlight is reddened by the same
atmos::TransmittanceLut(Rayleigh/Mie/ozone) that reddens the sky — as the sun'sμ_sun = sin(elevation)drops, blue is scattered out of the beam, so the low sun goes orange/red on its own. No second sunset model. - Night gate lives here, not in
atmos. The landed transmittance LUT has a below-horizon knife-edge (a near-straight-down sun reads as high transmittance), which alone makes deep night render brighter than day.daycyclemultiplies the sky tint bysky_scale = max(0.02, smoothstep(-8°, 2°, elevation))— full above the horizon, a civil-twilight glow just below, a faint star/moon floor at deep night. This corrects the artefact without touchingatmos.rsor its GPU oracle (L2). - Weather is a continuous lever (
cloudiness ∈ [0,1]), so overcast is monotone and testable, not a hard two-state switch.Weather::{clear, overcast, cloudy}. - Output is the shared
SunSky→light_uniform/sun_uniform/sky_uniformalready consumed bymap3d.wgsl+ the CPU painter. A caller swapsSunSky::noon()→DayCycle::sun_sky(hour, &atmos, alt)and gains the whole cycle.
Alternatives considered live in flightsim-engine-roadmap.md; this doc names only the shipped design.