Shading

Shading is deciding the color of every pixel — one small recipe (ambient + diffuse + specular) run at one of three frequencies: per face, per vertex, or per fragment. The recipe sets the material; the frequency sets the quality, and the specular highlight tells you which one you're looking at.

Core Idea

Shading is the pipeline’s last creative act: deciding the color of every pixel a surface covers. Two things fully determine the result — the recipe (which lighting terms are summed) and the frequency (how often the recipe runs). The three spheres above share one Blinn-Phong equation, identical geometry, the same light; only the frequency differs. Watch the specular highlight as you move the light: absent per face, smeared per vertex, crisp per fragment. The highlight is the tell.

The Recipe

The workhorse of realtime lighting is a sum of three terms, each doing one job:

color = ambient + diffuse · max(0, N·L) + specular · max(0, N·H)^shininess

Every input is a normal-against-direction comparison — the whole recipe is dot products wearing different hats.

Where the Recipe Runs

The same equation can run at three frequencies, and the sphere demo is an honest implementation of all three:

Frequency Runs How The highlight
per face (flat) once per triangle face normals; the vertex-stage result is constant across the face absent — a facet is one color
per vertex (Gouraud) once per vertex lighting in the vertex shader, colors interpolated across the triangle smeared or gone — the peak lives between vertices
per fragment (Phong) once per pixel normals interpolated instead, equation in the fragment shader crisp

Gouraud was the historical bargain — hundreds of vertices are cheaper than tens of thousands of fragments — and its failure mode is instructive: interpolating results loses everything sharper than the vertex grid. Interpolating inputs (the normal) and computing late keeps the detail. That’s the general lesson: compute at the frequency of the detail you want to keep.

Materials Are Bottled Shaders

A Three.js material is a pre-written shader with knobs. The tiers map straight onto cost: MeshBasicMaterial runs no lighting at all, MeshLambertMaterial stops at the diffuse term, MeshPhongMaterial is the full recipe above, and MeshStandardMaterial replaces the recipe with a physically-based integral — several times the per-pixel work. Because the fragment stage runs millions of times per second, this choice is one of the biggest fill-rate levers on mobile; swapping PBR for Lambert where correctness isn’t needed can roughly double the frame rate. For anything the built-ins can’t say — toon ramps, holograms, morphing fields — ShaderMaterial takes raw GLSL and the recipe becomes yours to rewrite.

Connections

The diffuse term is the dot product article’s whole subject, and every term consumes the normals that article keeps honest. The per-vertex → per-fragment story rides on barycentric interpolation, which rasterization performs for every varying of every triangle. Texturing feeds the recipe its per-pixel inputs — base color, roughness, even replacement normals — and the Three.js material tiers are the same recipe sold at different frequencies and fidelities.