Skip to content

Light & Normals

Move a light around a surface and watch the shading model respond, term by term.

What you should come away with: Why normals need the inverse-transpose, and what separates flat, Gouraud and Phong.

Assumes: The Model Matrix. It will still make sense without it, but that one comes first.

  • light
  • normals
drag or arrow keys to orbit

The shading equation

N = normalize(normalMatrix * normal)
L = normalize(lightDir)
H = normalize(L + V)

colour = base × (0.12
                 + 0.80 × max(0, N·L))
       + 0.50 × max(0, N·H)^32

Normal matrix (inverse-transpose)

1.000.000.00
0.001.000.00
0.000.001.00

A normal is not a position: it describes an orientation, so it does not transform like one. Scaling a sphere flat in y makes its surface shallower, which means the normals must tilt up, not get squashed down with the geometry. The inverse-transpose is what encodes that. Under uniform scale it reduces to the model matrix, which is why the mistake is invisible until the day someone scales one axis.

Where that leaves you

You can now say why a highlight follows you around the sphere while the diffuse shading stays painted on, and recognise the flattened-sphere signature of normals sent through the model matrix rather than its inverse-transpose.

This did not teach you shadows. Nothing on this site casts one, because a shadow is a second render pass rather than a lighting term.