Shading and Lighting

Render a plain grey sphere with no lighting at all and you get a flat, dead disc — a coin, not a ball. What turns that disc into a convincing three-dimensional object is shading: deciding, for every pixel on the surface, how bright it should be. And brightness, it turns out, is not a property of the surface alone — it depends on where the light is and which way the surface faces. Tilt a patch of surface toward the lamp and it glows; turn it away and it falls into shadow. That single geometric fact is the seed of almost all real-time lighting.

Now put two balls side by side under the same lamp — a matte rubber ball and a polished billiard ball. The matte one has a soft, even glow that changes gradually across its surface. The shiny one has that same soft glow plus a tight, brilliant white dot where the lamp reflects straight into your eye. Same light, same shape, wildly different look. A good lighting model has to reproduce both behaviours — and the classic one that does, taught in every graphics course since 1975, is the Phong reflection model.

The surface normal: which way a patch faces

Everything starts with the surface normal N — a unit vector sticking straight out of the surface at the point we are shading, perpendicular to it. The normal is how the geometry tells the lighting equation which way this little patch is pointing. A patch on the top of a sphere has a normal pointing up; a patch on the side has a normal pointing sideways. We also need L, the unit vector pointing from the surface point toward the light, and V, the unit vector pointing toward the viewer's eye. These three little arrows — N, L, V — are all the geometry the model needs.

Because N and L are both unit vectors, their dot product has a beautiful meaning: it is exactly the cosine of the angle \theta between them,

N \cdot L = |N|\,|L|\cos\theta = \cos\theta,

so N\cdot L is a ready-made "how well does this patch face the light?" dial, running from 1 (facing straight at the lamp) down through 0 (edge-on) to -1 (facing away).

Diffuse: Lambert's cosine law

A matte surface — chalk, paper, rough plastic — scatters incoming light equally in all directions. How bright it looks does not depend on where you stand; it depends only on how square-on the surface is to the light. A patch tilted at angle \theta to the incoming rays catches light spread over a larger area, so each point receives less — and the amount it receives falls off as \cos\theta. This is Lambert's cosine law, and it gives the diffuse term:

I_\text{diffuse} = k_d \,\max(0,\, N \cdot L).

Here k_d is the surface's diffuse colour/reflectivity (how much of each colour channel it bounces back). The \max(0,\,\cdot) is not decoration: when the light is behind the surface, N\cdot L goes negative, and a negative brightness is meaningless — we clamp it to 0 so a back-facing patch simply sits in shadow instead of glowing with "negative light". This one term alone already makes a sphere look round.

Turn the light and watch the patch respond

Below, the normal N points straight up out of the surface. Sweep the light direction L around with the slider and watch two things at once: the angle \theta between N and L, and the brightness of the illuminated patch on the right. When the light is overhead the patch blazes (N\cdot L = 1); as the light swings toward the horizon it dims to nothing (N\cdot L = 0); once the light drops below the surface the diffuse term clamps to 0 and the patch goes dark. That is Lambert's law, live.

Specular: the shiny highlight

Diffuse alone gives us the matte ball. To get the billiard ball's bright dot we add a specular term, which models a near-mirror bounce. Reflect the light direction L about the normal to get the ideal reflection direction R; the highlight is brightest when that reflected ray shoots straight into the viewer's eye, i.e. when R lines up with V. So we use R\cdot V, and raise it to a power to make the spot tight:

I_\text{specular} = k_s \,\big(\max(0,\, R \cdot V)\big)^{n}.

The exponent n is the shininess. A small n (say 4) gives a broad, soft sheen like brushed metal; a large n (say 128) squeezes the highlight into a tiny, mirror-like glint, because raising a number below 1 to a high power crushes it toward zero everywhere except right at the peak. k_s is the specular colour, usually white-ish, because a highlight is mostly the colour of the light, not the surface.

Putting it together: the Phong sum

Real scenes also have light bouncing around indirectly — from walls, the floor, the sky — filling in the shadows so they are never pitch black. Rather than simulate all of that, Phong adds a cheap constant ambient term. The full model is just the sum of the three:

I = \underbrace{k_a}_{\text{ambient}} \;+\; \underbrace{k_d\,\max(0,\,N\cdot L)}_{\text{diffuse}} \;+\; \underbrace{k_s\,\big(\max(0,\,R\cdot V)\big)^{n}}_{\text{specular}}.

Ambient sets a baseline glow everywhere; diffuse shapes the form as the surface turns toward and away from the light; specular drops the sparkle on top. Evaluate this once per pixel, per light, for each colour channel, and a bare grey disc becomes a shiny, rounded ball. It is not a physically exact simulation — but it is fast, tunable, and looks convincing, which is why it powered real-time graphics for decades and still shows up in shaders today.

Worked example: computing a diffuse value

Suppose the surface normal is N = (0, 1, 0) (pointing straight up) and the light direction is L = (0.6, 0.8, 0) — already a unit vector, since \sqrt{0.6^2 + 0.8^2} = \sqrt{0.36 + 0.64} = 1. The dot product is

N\cdot L = (0)(0.6) + (1)(0.8) + (0)(0) = 0.8.

That is positive, so no clamping is needed, and with a diffuse reflectivity k_d = 1 the diffuse brightness is \max(0,\,0.8) = 0.8 — the patch shines at 80% of full. Now swing the light below the surface to L = (0.6, -0.8, 0): the dot product becomes -0.8, the \max clamps it to 0, and the patch is correctly dark. Same arithmetic, one sign flip, all the difference between lit and shadowed.

The Phong reflection model above says how to compute brightness at a single point. A separate choice is where on the triangle you run it — and that choice has a bigger visual impact than beginners expect.