Graphics › Coordinate spaces
Aspect ratio & the viewport
NDC is a square; your window usually isn't. Bake the width-to-height ratio into the projection matrix or your perfect cube turns into an egg.
what the camera records
Rays converge on the eye, so the far object lands closer to the centre and is recorded smaller — that's the ÷ depth that gives a sense of distance. Widen the FOV and more of the scene crams onto the same image.
The squashing problem
NDC maps to a square(−1…1 in both x and y), but the viewport transform then stretches that square to fill a window that's, say, 1600×900. If the projection didn't account for it, that horizontal stretch (1600/900 ≈ 1.78×) would make every circle an ellipse and every cube a shoebox.
The fix: aspect ratio in the projection matrix
Define aspect = width / height and divide the x-scale of the projection matrix by it. In a perspective projection the matrix's [0][0] entry becomes (1 / tan(fov/2)) / aspect: the x direction is “pre-squeezed” by exactly the amount the viewport will later stretch it, so the two cancel and shapes come out true. Convention is to keep the vertical FOV fixed and let the horizontal FOV widen on wide screens (“Hor+”).
Resize handling, in one line
aspect = newWidth / newHeight. Do one but not the other and you get stretched graphics or a scene that doesn't fill the window.Letterboxing & pillarboxing
When you must preserve a specific framing (a cutscene, a fixed-camera puzzle), you instead pick a target aspect and add black bars: shrink the viewport to that ratio and centre it — letterbox (bars top & bottom) on a too-wide window, pillarbox (bars left & right) on a too-tall one. The projection stays fixed; only the viewport rectangle changes.
Orthographic cameras need it too
An orthographic camera defined by a half-height h should use half-width h · aspect, for the same reason — otherwise your 2D/isometric scene scrolls faster horizontally than vertically.