Reflection

A mirror does one thing, perfectly: it takes an incoming ray and sends it back out at the same angle, on the other side of the surface. A raytracer needs that bounce as a formula — given the direction a ray is travelling and the surface normal it strikes, what direction does it leave in? The whole answer is one line,

\vec{R} = \vec{D} - 2(\vec{D}\cdot\vec{N})\,\vec{N},

where \vec{D} is the incoming direction, \vec{N} is the unit surface normal, and \vec{R} is the reflected direction. Let's not assert it — let's build it, and watch the angle come out equal on its own.

Deriving the bounce, line by line

Step 1 — split the incoming ray into two parts. Any vector hitting the surface can be written as the part that points along the normal (straight into the surface) plus the part that lies in the surface (sliding sideways):

\vec{D} = \vec{D}_{\parallel} + \vec{D}_{\perp},

where \vec{D}_{\parallel} runs along \vec{N} and \vec{D}_{\perp} runs across it (perpendicular to \vec{N}, i.e. tangent to the surface).

Step 2 — measure the normal part with a dot product. Because \vec{N} is a unit vector, the projection of \vec{D} onto it is just the dot product \vec{D}\cdot\vec{N} times \vec{N}:

\vec{D}_{\parallel} = (\vec{D}\cdot\vec{N})\,\vec{N}.

Step 3 — the surface part is whatever's left over. Rearranging Step 1,

\vec{D}_{\perp} = \vec{D} - \vec{D}_{\parallel} = \vec{D} - (\vec{D}\cdot\vec{N})\,\vec{N}.

Step 4 — reflect by flipping only the normal part. Here is the entire idea of a mirror. A bounce reverses the component going into the wall while leaving the sideways slide untouched — the ray skids along the surface the same way, but its "into the wall" motion becomes "out of the wall". So negate \vec{D}_{\parallel} and keep \vec{D}_{\perp}:

\vec{R} = \vec{D}_{\perp} - \vec{D}_{\parallel}.

Step 5 — substitute the two pieces back in. Putting Step 2 and Step 3 into Step 4,

\vec{R} = \big[\vec{D} - (\vec{D}\cdot\vec{N})\,\vec{N}\big] - (\vec{D}\cdot\vec{N})\,\vec{N}.

Step 6 — collect the two identical terms. Both carry the factor (\vec{D}\cdot\vec{N})\,\vec{N}, so they add to twice it:

\vec{R} = \vec{D} - 2(\vec{D}\cdot\vec{N})\,\vec{N}.

That's the reflection formula — three multiplies and a subtract per axis, and it's the beating heart of every mirror in every raytraced frame.

Step 7 — check the angle really is preserved

A bounce should obey "angle in equals angle out". First, reflection keeps the ray's length: squaring \vec{R} and expanding the dot product,

\vec{R}\cdot\vec{R} = \vec{D}\cdot\vec{D} - 4(\vec{D}\cdot\vec{N})(\vec{D}\cdot\vec{N}) + 4(\vec{D}\cdot\vec{N})^2\,(\vec{N}\cdot\vec{N}).

Since \vec{N} is a unit vector, \vec{N}\cdot\vec{N} = 1, so the last two terms cancel and \lVert\vec{R}\rVert = \lVert\vec{D}\rVert. Next, the angle each ray makes with the normal is read off by dotting with \vec{N}:

\vec{R}\cdot\vec{N} = \vec{D}\cdot\vec{N} - 2(\vec{D}\cdot\vec{N})(\vec{N}\cdot\vec{N}) = \vec{D}\cdot\vec{N} - 2(\vec{D}\cdot\vec{N}) = -(\vec{D}\cdot\vec{N}).

Same magnitude, opposite sign: the outgoing ray leans away from the normal by exactly the angle the incoming ray leaned toward it. Angle of incidence = angle of reflection, proven, not assumed.

Let \vec{D} be an incoming direction striking a surface with unit normal \vec{N}. The reflected direction is \vec{R} = \vec{D} - 2(\vec{D}\cdot\vec{N})\,\vec{N}, and it has these properties:

Two silent bugs hide in this one line. First, \vec{N} must be unit length — Step 7's proof of "angle in equals angle out" leaned directly on \vec{N}\cdot\vec{N} = 1. Feed it a normal that's twice as long and the reflected ray doesn't just come out twice as long: the term 2(\vec{D}\cdot\vec{N})\,\vec{N} gets scaled by the length twice (once in the dot product, once in the trailing \vec{N}), so the bounce is silently wrong in both size and direction. Always renormalize a normal you compute yourself — say, from a cross product of two edges — before reflecting with it.

Second, mind the sign convention of \vec{D}. This page's formula assumes \vec{D} points into the surface — the direction the ray is actually travelling. Some libraries instead hand you the direction pointing back toward the ray's origin. Mix the two conventions — say, by plugging in a flipped \vec{D} without flipping the formula — and every reflected ray comes out pointing backwards. Pick one convention and stay consistent with it everywhere in your raytracer.

The same bounce powers two things that look different on screen. A mirror (a perfectly smooth surface) reflects the scene: the raytracer follows \vec{R} off into the world and shows whatever it hits — this is the recursive reflection ray you'll meet later.

A specular highlight — that bright glint on a glossy apple — is the same reflection applied to the light rather than the scene. The surface looks brightest where the reflected light direction points straight at your eye, so the glint sits exactly where \vec{R} lines up with the view. Both are \vec{R} = \vec{D} - 2(\vec{D}\cdot\vec{N})\,\vec{N} wearing different costumes; we'll meet the highlight again in the lighting equation.