Math Playground
Back to Graphics

Graphics › Coordinate spaces

Clip space & NDC

After projection, the whole visible world has been crammed into a tidy cube from −1 to 1. Anything that pokes outside it gets clipped away.

Coordinate spaces — follow a cube from mesh to pixels
xyz

Model space: the cube as the mesh file stores it — built around its own origin, no idea where it'll end up.

the cube's far-top-right corner here: (0.5, 0.5, 0.5)

Clip space: the “before the divide” space

Multiply a view-space point by the projection matrix and you land in clip space — a 4D coordinate (x, y, z, w)where, conveniently, a point is visible exactly when −w ≤ x ≤ w, −w ≤ y ≤ w, and −w ≤ z ≤ w. The GPU does the actual clippinghere: triangles straddling the boundary get cut along it, brand-new vertices generated on the edge, so nothing outside the view ever reaches the rasterizer.

NDC: after the perspective divide

Divide x, y, z by w (the perspective divide) and you get Normalized Device Coordinates: every visible point now has x, y, z all between −1 and 1. (Direct3D uses 0…1 for z; OpenGL uses −1…1 — another API gotcha.) NDC is resolution-independent: it doesn't know or care whether the window is 800 px or 4K — that's the next step, screen space.

Why clip before the divide?

A point behind the camera has negative w. Divide first and it wraps around to the wrong side of the screen — a triangle with one vertex behind you would render as a torn mess. Clipping in 4D clip space (against the ±w planes) cleanly removes those parts first, so the divide only ever sees points in front.

The depth buffer lives here too

That NDC z (remapped to 0…1) is what goes into the depth buffer: for each pixel the GPU keeps the smallest z so far, so nearer surfaces hide farther ones. Because of the perspective divide, depth precision is concentrated near the camera — which is why far-away coplanar surfaces are the ones that z-fight.