A player clicks the screen. They mean “that goblin” — but all the engine
receives is a 2-D pixel,
Forward, the pipeline flattens 3-D world points down to 2-D pixels and throws depth away. We can't un-flatten a single point — a pixel corresponds to a whole line of world points stacked behind it, every one of which renders to the same spot. That line, from the camera out through the pixel, is the answer: the pick ray.
Step 1 — lift the pixel to normalised device coordinates. The MVP pipeline's
output lives in the
(The
Step 2 — choose two depths to pin the line. A pixel is one
These two NDC points sit on the same screen pixel but at opposite ends of the view frustum — so the world line through them is exactly the line the camera sees through that pixel.
Step 3 — un-project both with the inverse pipeline. Apply the
Equivalently, apply
Step 4 — assemble the pick ray. The ray starts at the camera (the near point) and aims toward the far point:
This is the camera-through-pixel ray: the unique world line that the chosen pixel looks down.
Step 5 — intersect the scene and take the nearest hit. Now hand the ray to the
intersection tests you already have —
Smallest positive
Once you can cast a ray from a pixel, a whole family of features falls out of the one mechanism. A hitscan weapon — a rifle, a laser — fires not a projectile but a ray straight down the crosshair (the centre pixel), takes the nearest hit, and applies damage there the same frame: no travel time, no drop. Mouse selection in an RTS or an inventory casts from wherever the cursor sits and picks the unit under it.
Level editors lean on the inverse direction hardest of all: “drop this prop where I clicked on the floor” un-projects the cursor to a ray and intersects it with the ground plane, converting a 2-D click into a 3-D placement. Drag-to-move, the terrain brush, the gizmo you grab to rotate an object — all of it is cursor-to-world un-projection. The pick ray is the bridge every time the player or the designer reaches into the screen.
Un-projecting a pixel means undoing every stage of the forward pipeline — viewport, perspective divide, projection, view — and undoing them in the reverse order, each with its own inverse operation. Get one stage wrong — forget the perspective divide, invert the view and projection matrices in the wrong order, skip the y-flip between pixel rows and NDC, or apply the inverse of only the view matrix and not the projection — and nothing crashes. You still get a ray: it starts somewhere plausible and points off in some direction. It's just the wrong direction, so clicks silently select the wrong object, or nothing at all, at some screen positions or camera angles but not others.
That's why picking bugs have a nasty reputation: the ray is almost right, so the
symptom is never an error message — it's "clicking near the edge of the screen selects the
wrong unit" or "picking works when the camera looks straight ahead but breaks the moment it
rotates." The fix is always the same discipline: write down the forward pipeline stage by
stage (model → view → projection → perspective divide → viewport), then
invert it stage by stage in the exact opposite order (viewport-1 → divide out