logo
By Lawrence

14 minutes

Night and Headlights

The clock has not moved since lesson 1.4. It still reads 16:12. Start it at the scene's speed and the sun sets 43 s after you load. Six seconds later it is night, and not one car on the road has a light.

The dark brings two jobs. The one light in the sky has to change from sun to moon without a jolt. And every car needs headlights, on a renderer that can only afford a few real lights.

Sun and moon

The clock drives two lights, the Sun and the Ambient fill. There is no moon light. When the sun goes down, the Sun entity's light becomes the moon, and dayLightAt decides each frame which of the two it is:

src/components/DayNightCycle/DayNightCycle.core.ts
// The sun's track: up from `sunAzimuth`, across, and down the far side.
const along = ((h - 6) / 12) * Math.PI; // 0 at sunrise, π at sunset
const elev = Math.asin(Math.max(-1, Math.min(1, sh)));
const sunCos = Math.cos(Math.max(0.12, elev));
const az = look.sunAzimuth;
const sunToward: [number, number, number] = [
  Math.cos(along) * Math.cos(az) * sunCos,
  Math.max(0.12, Math.sin(Math.max(0.12, elev))),
  Math.cos(along) * Math.sin(az) * sunCos + 0.35,
];
// The moon rides high and a little to the side, so night shadows still fall.
const moonToward: [number, number, number] = [-0.35, 0.86, 0.38];

const sunI = look.sunIntensity * smoothstep(-0.06, 0.32, sh);
const moonI = look.moonIntensity * smoothstep(-0.02, -0.3, sh);
const useSun = sunI >= moonI;
const toward = useSun ? sunToward : moonToward;
const len = Math.hypot(toward[0], toward[1], toward[2]) || 1;
const keyDirection: [number, number, number] = [-toward[0] / len, -toward[1] / len, -toward[2] / len];

sh is the sun's height from lesson 1.4, and it is a height, not the light's angle. sunToward points at the sun, but its height part never drops under 0.12 and its z gets a fixed lean of 0.35. So at sunset, when sh reaches 0, the light still comes down at 8°. The moon gets one fixed direction, high and to the side.

Each light's strength comes from the smoothstep from lesson 1.5, a ramp that starts and ends gently. With our scene's numbers:

Continue reading

Unlock the Full Course

Every lesson, the runnable examples, and the finished build — yours to keep.

$9one-time

Was this page helpful?

We read every note — tell us what's working and what isn't.

↑↓ NavigateEnter SelectEsc CloseCtrl+K Open Search