Task 5 of 6
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).
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).(lx, ly, lz)Math.max(dot, 0.0) — no negative lightc = 0.15 + 0.85 * diffthis.color(c, c * 0.62, c * 0.86, 1)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.
const diff = Math.max(nx / len * lx + ny / len * ly
+ nz / len * lz, 0.0);
const c = 0.15 + 0.85 * diff;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.
This page is an interactive exercise — the editor, the GPU runner and your saved progress need JavaScript. The text above is the full brief.