# Perspective Projection

Short Version:

Given:

Input values
Symbol Meaning Typical value
$$fov$$ Field of view 45 – 90 degrees
$$aspect$$ Aspect ratio around 1.8 – use frame buffer Width / Height
$$z_{near}$$ distance from camera to near clip plane in Z +1
$$z_{far}$$ distance from camera to far clip plane. MUST be greater than zNear. 1000

You’ll need to calculate a few values before populating the matrix:

Intermediate derived values
Symbol Meaning Formula
$$halfHeight$$ half of frustum height at $$z_{near}$$ $$z_{near} * \tan{\frac{fov}{2}}$$
$$halfWidth$$ half of frustum width at $$z_{near}$$ $${halfHeight}\times{aspect}$$
$$depth$$ depth of view frustum $$z_{far}-z_{near}$$

Then, just populate your matrix:

$$\large \begin{bmatrix} \frac{z_{near}}{halfWidth} & 0 & 0 & 0 \\ \\ 0 & \frac{z_{near}}{halfHeight} & 0 & 0 \\ \\ 0 & 0 & \frac{-({z_{far}} + {z_{near}})}{depth} & -1 \\ \\ 0 & 0 & -2\times\frac{z_{far} \times z_{near}}{depth} & 0 \\ \end{bmatrix}$$

## Explanation

Basically, this takes a vertex in camera space (see note on coordinate spaces), and scales it so that every vertex that is contained within the view frustum fits within a (-1:+1) cube. The rasterizer, a non-programmable hardware stage that executes after the vertex shader but before the fragment shader, divides each vertex by it’s W component.

Avoiding a long and sticky explanation for the moment:

Any point that lies within the view frustum will, after processed by the rasterizer, fit within a 2×2 cube centered at the origin. Any part of a primitive that lies within that space will trigger a call to the fragment shader. Anything outside of that cube will be “clipped” by the rasterizer, and will not render – since it does not exist on screen.

Better explanation required.