Paint an image onto a surface — and get the perspective right. Each vertex carries a texture coordinate u; across a tilted triangle the coordinate cannot be interpolated straight in screen space, or the picture swims. Catmull's fix: carry u/w and 1/w, interpolate those linearly, and divide at the pixel. Down the center: texture coordinates go in, the engine interpolates, the true surface UV comes out. Blue builds it; red makes it warp.
source P. Heckbert, Survey of Texture Mapping, IEEE Computer Graphics & Applications, Nov. 1986, pp. 56–67 — doi:10.1109/MCG.1986.276672 (after E. Catmull, PhD thesis, Utah, 1974). Rendered, not quoted.
A vertex has a texture coordinate u and a clip-space depth w. Screen position goes as x/w, so u is not linear in screen space — but u/w and 1/w both are.
Correct. At screen fraction t along an edge:
u = [(1−t)·u₀/w₀ + t·u₁/w₁] / [(1−t)/w₀ + t/w₁]
For the current edge (u₀=0→u₁=1, w₀=1→w₁ below), live comparison of the three interpolants at the sample point:
| method | u at sample | matches surface? |
|---|
Catmull (1974) first mapped an image onto a curved surface; Heckbert (1986) surveyed and named the machinery. The divide-by-1/w is not special to edges — it is barycentric interpolation done in homogeneous space: weight each vertex attribute by 1/w, sum, and divide by the summed 1/w.
That is why a floor tiled with a checker does not warp: the per-pixel 1/w restores true surface distance. Each sphere is the next one's premise — see the-barycentric, where the same weights live in the plane before w ever enters.
The blue team's live check: re-run the interpolants over the whole edge and confirm the perspective-correct one equals the true surface UV to 1e-9, while the screen-linear one does not. If red tampers, this badge is where it shows.
Two vertices of a tilted triangle. Vertex 0 is near (small w); vertex 1 is far (large w). Each carries a surface coordinate u — the position on the image — plus its depth w:
| vertex | u (surface) | w (depth) |
|---|---|---|
| 0 · near | 0.0 | 1.0 |
| 1 · far | 1.0 | 3.0 |
The pixels between them are found by walking a screen fraction t from 0 to 1. The question the panel answers: which u belongs at fraction t? Straight-line guessing is wrong the instant w₀≠w₁.
Perspective-correct: interpolate u/w and 1/w, then divide. Recovers the true surface point.
Two floors, one checker texture. Left: affine — u interpolated straight in screen space; the tiles stretch and swim toward the horizon. Right: perspective-correct — the same tiles keep their true surface spacing. Everything computed per pixel, never looked up.
What the machine produces, proven: at every screen fraction t the perspective-correct interpolant equals the exact 3D-to-UV mapping (verified from the actual line geometry to 1e-9), while the screen-linear one is measurably wrong on any tilt. At the vertices both agree — there w is shared and the divide is a no-op.
The blue team's witness (left) confirms this live; the red team (right) makes u swim.
And it is only step one: nearest-texel lookup on a minified surface aliases — the checker sparkles at distance. The honest fix is filtering (mipmaps, anisotropic) — a whole second machine this sphere does not build. Getting the coordinate right is necessary, not sufficient.
"Just lerp the UVs across the triangle." Cut. Screen-linear u is only correct when w₀=w₁ (no tilt). On any depth gradient it warps — the whole reason for the divide.
"Interpolate w, then divide u by it." Cut. w is not linear in screen space; 1/w is. You must interpolate the reciprocal, not the depth.
"Perspective correction is a texture trick." Kept, corrected. It is every varying — colour, normals, UVs all ride the same 1/w divide. Texture is only where the eye first catches the error.
The red team's move: skip the divide by the interpolated 1/w and interpolate u straight in screen space. The texture swims; the blue team's witness (window 7) is watching.
Drop the perspective divide and the engine returns the screen-linear u — the panel's "correct" floor starts to swim, and the witness recomputes, disagrees with the true surface UV, and turns red. Nothing is faked; the attack is real and it is caught.