Faking geometry with a texture
Normal mapping lab
A normal map does not add surface. It replaces the normal vector the lighting equation uses, per pixel, from a texture — so the surface reflects light as though the detail were there. Drag the light across any pane: the middle surface is two triangles pretending, the right one is the real thing. Then flatten the view angle and watch the pretence break at the silhouette.
Every pixel uses the same normal, straight up out of the quad, so the lighting is a single smooth gradient. The colour texture alone cannot make light behave.
The same two triangles. Each pixel looks up its own normal in the map, so highlights slide over the rivets exactly as they would over real ones — and it costs one texture fetch.
The detail modelled honestly, as vertices. It is correct at every angle and it costs thousands of times more triangles for a result that is nearly identical head-on.
Pull view angle down towards 8° to graze the surface. Pane 2's outline stays a perfectly straight edge no matter how bumpy it looks — the geometry never moved.
Hover the map on the left. Nothing here is a colour — the three channels are a direction, packed into 0–1 because that is all an 8-bit texture can hold.
decode n = 2·rgb − 1 → [−1, 1]
"no change" n = (0, 0, 1)
re-encode rgb = (0.5, 0.5, 1.0)
A texel that says "leave the normal alone" encodes to (128, 128, 255) — that flat periwinkle blue. A normal map is mostly "no change", which is why the whole image is mostly that one colour. The deviations are the detail.
Red leans the normal along the surface's tangent, green along its bitangent, blue straight out. Because the vectors are expressed in that local frame rather than in world space, the same map works on a flat plate, a cylinder or a character's cheek.