crispigt.

the lighting was wrong

Two days after building the donut, I realized I got the lighting wrong in two places.

First, I check L > 0 before writing to the z-buffer. That lets lit surfaces behind an unlit surface show through. Depth-test first, update depth for every closer sample, then check L and write the character, including a space when it's dark. An unlit surface still blocks the camera.

Second, the dot product only tells me whether the surface faces the light. Another part of the torus can still block it. I never check that.

The easiest fix is probably another z-buffer from the light's view. Render depth there first, then compare each visible point against it. For this fixed light direction, use an orthographic projection. Anything behind the stored depth is in shadow, with a small bias to avoid self-shadowing artifacts. That's a shadow map. Haven't implemented it yet.