Perspective Projection

There is No Camera

When we watch a film the images we see are captured from a video camera, naturally when see a video game there is an assumption that somewhere in the code there is a virtual camera. When you program directly to a graphics API like OpenGL though most people are surprised to learn that there is in fact really no camera. The feeling of a camera capturing things in our virtual world is an illusion created through the use of the Perspective Projection Matrix and a stage of the rendering pipeline called Perspective Divide.

The purpose of this page is to explain what the perspective projection matrix and perspective divide do, not on the stages of the rendering engine, please look here for information on the rendering pipeline of OpenGL.

What happens after we call draw()

When we call the draw() command in OpenGL we start the rendering process. We supply to OpenGL the vertices of all the objects we wish to draw, and the matrices which will transform our objects.

The vertex shader that we have supplied to OpenGL is then invoked for every vertex. It is in the vertex shader that we carry out the matrix multiplication used to compute the final position of our vertices.

After applying all our object and world matrices to our vertex we have the final position of our vertex in world coordinates and are ready to set the variable gl_Position. Before this the last thing we do is apply our Perspective Projection Matrix. The last bit of code in your vertex shader might look a little something like this:

Vertex Shader Source Code (GLSL)

void main(void) {
//code where we calculate worldPosition
vec4 projectionPosition = projectionMatrix * worldPosition;
gl_Position = projectionPosition;

After we have set gl_Position and our call to the vertex shader has ended, later on in the rendering pipeline, during vertex post processing perspective divide is applied. We don’t do this ourselves or call any command, rather this is an automatic part of the rendering pipeline.

What does our Matrix Look Like?

Let \( T_P \) be a perspective projection matrix. \( T_P \) is a function of the arguments( left, right, top, bottom, near, far). We usually abbreviate these arguments with their first letter, ( l, r, t, b, n, f) the matrix to the right shows the components of \( T_P \). Changing these arguments changes what our matrix will do.

Read more about Perspective projection here

Perspective Projection Matrix

\( T_P = \left[\begin{matrix}\frac{2n}{r-l}&0&\frac{r+l}{r-l}&0\\0&\frac{2n}{t-b}&\frac{t+b}{t-b}&0\\0&0&\frac{-(f+n)}{f-n}&\frac{-2fn}{f-n}\\0&0&-1&0\\\end{matrix}\right] \)

What does our Matrix do?

The illusion of a virtual camera rendering what we see on our screens is the result of the perspective projection matrix and perspective divide working together.

The perspective projection matrix does two main things:

1.The arguments ( l, r, t, b, n, f) define a rectangular prism, and any vector contained within this rectangular prism is mapped into a unit cube. This unit cube has sides of length 2, and occupies the volume \( -1 \leq x \leq 1 \), \( -1 \leq y \leq 1 \), \( -1 \leq z \leq 1 \).

Why is this useful? The projection matrix gives us the freedom to define objects with convenient coordinates. If we didn’t have this we would always have to define our objects to be within the unit cube and many times this is inconvenient. By changing the arguments of the matrix we can control how much of our world is shown on the screen.

2. The projection matrix increases the w component of our vertex as a function of the vertex’s z component. The w component of our vertex will be equal to \( -1 v_z \) where \( v_z \) is the z component of our vertex.

Why is this useful? In perspective divide we divide each component of our vertex by w (shown to left). Since the matrix increases the w component of our vertex when we do perspective divide we in a sense are dividing by z. Vertices with larger z components, which are farther away from us have their w component increased after being multiplied by the projection matrix and when perspective divide is done this vertex will move closer to the origin.

Perspective Divide

\( \begin{pmatrix} x \\ y \\ z \\ w \end{pmatrix} \mapsto \begin{pmatrix} \frac{x}{w} \\ \frac{y}{w} \\ \frac{z}{w} \end{pmatrix} \)

touch_appMake Your Own Projection Matrix

The program below lets you specify the arguments ( l, r, t, b, n, f) for the projection matrix. Using the matrix you specified see where any vector is mapped to after projection and perspective divide, as well as seeing the effect of your matrix on the scenes below.

tuneTune Projection Settings

Use the sliders below to change the settings of the projection matrix & see how it affects the animation to the right. Changes to the matrix are used in computing the transformation of \( \overrightarrow{a} \) below.

\( left = \) -1.0

\( top = \) 1.0

\( near = \) 1.0

\( right = \) 1.0

\( bottom = \) -1.0

\( far = \) 10.0

See how the vector \( \overrightarrow{a} \) is transformed after being transformed by the projection matrix and after perspective divide. Change the components of \( \overrightarrow{a} \) using the vector object below and press the blue button to calculate the final position of \( \overrightarrow{a} \).

\( \overrightarrow{a} \) After Perspective Projection Transformation

\( \overrightarrow{a} \) After Perspective Divide