Coordinate spaces

02-coordinate-spaces.md · updated 2026-10-15

A vertex is quoted in six different spaces on its way to the screen, and every matrix in the chain is just a change of address. The geometry never changes, only what the numbers are measured against. Almost every "invisible / inside-out / in the wrong place" bug is a vertex sitting in the wrong space.

The chain

model → world → view → clip → NDC → screen.

Why w exists

Perspective is a division, and matrices can't divide — so the matrix saves the divisor in w and the hardware does it afterwards.

Things look smaller with distance because screen position is x / distance. A 4×4 matrix can only add and scale, so the projection matrix copies the view depth into w and leaves it there; after clipping, the GPU divides. That is also why clipping happens before the divide, where the test is the tidy −w ≤ x ≤ w and nothing has yet blown up by dividing by zero.

Orthographic projection sets w = 1, so the divide does nothing and distance stops shrinking things — right for UI, maps and CAD views.

Near and far

Depth precision is spent near the camera, so a tight near plane costs you everywhere.

Depth after the divide goes as 1/z, so halving the near plane roughly halves usable precision at every other distance. Near 0.01 with far 10 000 is a recipe for z-fighting at mid range. Push near out as far as the game tolerates; the far plane barely matters by comparison.

The two silent bug factories

Handedness — right-handed (OpenGL-style, camera looks down −z) versus left-handed (D3D-style, +z forward). Mix conventions and geometry ends up behind the camera, or faces get culled inside-out.

Row- vs column-major — same sixteen floats, two different meanings. Column vectors multiply M * v and compose right-to-left (P * V * M * v); row vectors multiply v * M and compose left-to-right. Guessing wrong gives a transposed matrix: rotations become shears and translation lands in the wrong row.

Demo

The same two cubes in all six spaces — flip between view and NDC to watch the frustum straighten into a box, and read the tracked corner's numbers change line by line.

Gotchas

Symptom Cause
Object invisible, maths looks rightIt is behind the camera (+z in a −z-forward world), or inside the near plane
Scene is a sheared messRow/column-major mismatch — transpose the upload
Everything drawn inside-out or culledHandedness flipped, so winding reversed
Objects wobble or flicker at distanceNear plane far too small; depth precision exhausted
Lighting wrong only on scaled objectsNormals transformed by the model matrix instead of its inverse-transpose
Vertices explode near the cameraDividing by w yourself, pre-clip, with w ≈ 0
FOV change makes objects move, not zoomVertical and horizontal FOV confused, or aspect applied twice

Open the demo →

← all notes & demos