Task 5 of 6

Turn On the Light

With normals in hand, lighting is one dot product. Lambert's law: a surface facing a light head-on catches full brightness; tilt it away and brightness falls with the cosine of the angle — which is exactly n · l, the dot product of the unit normal and the unit direction toward the light. Clamp it at zero so surfaces facing away go dark instead of negative.

Two finishing touches make it look right: an ambient floor of 0.15 so shadowed sides stay readable, and an albedo tint — multiply the final brightness into the metaball's pink (1.0, 0.62, 0.86).

Goal: light each hit point with c = 0.15 + 0.85 * Math.max(nx * lx + ny * ly + nz * lz, 0) and paint this.color(c, c * 0.62, c * 0.86, 1).

Requirements

Hint 1 — sanity-check the center

The center pixel's normal is (0, 0, -1) and the light is (-0.6, 0, -0.8), so the dot product is 0.8 and c = 0.15 + 0.85 × 0.8 = 0.83 — a bright, not-quite-white pink.

Hint 2 — the two lines
const diff = Math.max(nx / len * lx + ny / len * ly
  + nz / len * lz, 0.0);
const c = 0.15 + 0.85 * diff;

Same idea elsewhere

max(dot(n, l), 0.0) is character-for-character the same in GLSL, WGSL, HLSL and Metal Shading Language — Lambert diffuse may be the single most portable line of shading code in existence.

All tasks in Ray-Marched Metaballs

  1. The Sphere as a Number
  2. Two Spheres Melt Into One
  3. March Until You Hit Something
  4. Normals Without Geometry
  5. Turn On the Light
  6. Soft Shadows, Full Scene

This page is an interactive exercise — the editor, the GPU runner and your saved progress need JavaScript. The text above is the full brief.