Computer graphics is less about knowing when to apply algorithms and more about knowing *where*. There are many possible wheres. Our 3D models are born in *model space*. To situate models in the virtual world, their model space coordinates are transformed into *world space*. Many lighting algorithms are applied in *camera* or *eye space*. From eye space, we pass on into *clip space*, *normalized device space*, and *screen space*.

In this post, we’ll restrict our discussion to the transformation that turns world space coordinates into eye space coordinates. We’ll call the matrix that performs this transformation the view matrix $\mathbf{V}$. What does $\mathbf{V}$ look like? When I first learned computer graphics, the structure of the view matrix was just handed down to me from on high. But you can only do so much with someone else’s magic.

We have the following four constraints to help us figure out what $\mathbf{V}$ looks like.

- The viewer’s right arm should extend along the x-axis in eye space.
- The viewer should be standing along the y-axis in eye space.
- The viewer should be looking along the z-axis in eye space.
- The viewer should be standing at the origin in eye space.

Let’s make our constraints a bit more precise by considering how the transformation turns world space coordinates into eye space coordinates.

- The vector leading out the viewer’s right arm in world space is $\mathbf{r}$. When we use $\mathbf{V}$ to transform $\mathbf{r}$, we should get the x-axis, like this: $$\mathbf{V} \times \begin{bmatrix} r_x \\r_y \\r_z \\ 0 \end{bmatrix} = \begin{bmatrix} 1 \\0 \\0 \\0 \end{bmatrix}$$
- The vector leading up out of the viewer’s head in world space is $\mathbf{u}$. When we use $\mathbf{V}$ to transform $\mathbf{u}$, we should get the y-axis, like this: $$\mathbf{V} \times \begin{bmatrix} u_x \\u_y \\u_z \\ 0 \end{bmatrix} = \begin{bmatrix} 0 \\1 \\0 \\0 \end{bmatrix}$$
- The vector leading along the viewer’s focal or forward direction in world space is $\mathbf{f}$. When we use $\mathbf{V}$ to transform $\mathbf{f}$, we should get the z-axis, like this: $$\mathbf{V} \times \begin{bmatrix} f_x \\f_y \\f_z \\ 0 \end{bmatrix} = \begin{bmatrix} 0 \\0 \\1 \\0 \end{bmatrix}$$
- The viewer’s position in world space is $\mathbf{p}$. When we use $\mathbf{V}$ to transform $\mathbf{p}$, we should get the origin, like this: $$\mathbf{V} \times \begin{bmatrix} p_x \\p_y \\p_z \\ 1 \end{bmatrix} = \begin{bmatrix} 0 \\0 \\0 \\1 \end{bmatrix}$$

We can put these four vector multiplications together into a single matrix-matrix multiplication.

$$\mathbf{V} \times \begin{bmatrix} r_x & u_x & f_x & p_x \\r_y & u_y & f_y & p_y \\r_z & u_z & f_z & p_z \\ 0 & 0 & 0 & 1\end{bmatrix} = \begin{bmatrix} 1 & 0 & 0 & 0 \\0 & 1 & 0 & 0 \\0 & 0 & 1 & 0 \\0 & 0 & 0 & 1\end{bmatrix}$$

Notice the structure of our matrix of viewer parameters. It is the product of a translation matrix $\mathbf{T}$ and a rotation matrix $\mathbf{R}$. Additionally, the right-hand side is the identity matrix.

$$\begin{array}{rcl}\mathbf{T} &=& \begin{bmatrix}1 & 0 & 0 & p_x \\0 & 1 & 0 & p_y \\0 & 0 & 1 & p_z \\0 & 0 & 0 & 1 \end{bmatrix} \\\mathbf{R} &=& \begin{bmatrix}r_x & u_x & f_x & 0 \\r_y & u_y & f_y & 0 \\r_z & u_z & f_z & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} \\\mathbf{V} \times (\mathbf{T} \times \mathbf{R}) &=& \mathbf{I} \\\end{array}$$

Let’s solve for $\mathbf{V}$. We pull a few identities out of our hat to make this happen. First, multiplying a matrix by its inverse turns it into the identity matrix. Second, multiplying a matrix by the identity yields the original matrix. Third, the inverse of a product is the product of its operands’ inverses, commuted.

$$\begin{array}{rcl}\mathbf{V} \times (\mathbf{T} \times \mathbf{R}) \times (\mathbf{T} \times \mathbf{R})^{-1} &=& \mathbf{I} \times (\mathbf{T} \times \mathbf{R})^{-1} \\\mathbf{V} &=& (\mathbf{T} \times \mathbf{R})^{-1} \\\mathbf{V} &=& \mathbf{R}^{-1} \times \mathbf{T}^{-1} \\\end{array}$$

In separating our parameter matrix into $\mathbf{R}$ and $\mathbf{T}$, we have made finding the inverses easier. The job of the inverse of a transformation is to undo the transformation. The inverse of a translation, then, is just a translation by the negative offsets. The inverse of a rotation matrix “unrotates,” and the inverse just happens to be the transpose—though I do not find this obvious. Therefore, we have the following construction for $\mathbf{V}$:

$$\begin{array}{rcl}\mathbf{V} &=& \mathbf{R}^\textrm{T} \times \mathbf{T}^{-1} \\\mathbf{V} &=& \begin{bmatrix} r_x & r_y & r_z & 0 \\u_x & u_y & u_z & 0 \\f_x & f_y & f_z & 0 \\ 0 & 0 & 0 & 1\end{bmatrix} \times \begin{bmatrix}1 & 0 & 0 & -p_x \\0 & 1 & 0 & -p_y \\0 & 0 & 1 & -p_z \\0 & 0 & 0 & 1\end{bmatrix}\end{array}$$

One could also arrive at this matrix by thinking of it as a translation of the viewer to the origin and then a rotation the viewer’s frame to align with the standard axes. I prefer the construction above because I don’t trust myself to understand rotation matrices.

## Comments

I had to look at your source to figure out how you got such nice mathematical equations. In my feed reader, they came through as TeX formulae. I’ll need to keep MathJax in mind for my own web dev.

What inspired this article?

Hi, Paul. Yes, I discovered MathJax a couple of years ago. It’s much nicer than my old system of generating images or linking to PDFs. I use Feedly and see the source as well. All the mathy blogs I follow reveal their LaTeX source in Feedly.

In the spring I’m teaching computer graphics for the first time after a hiatus of several years, and I’ve been trying to remind myself why I know the things I know. My mathematics understanding degenerates very quickly into procedural knowledge.

Also, I’ve been working on a 3D turtle geometry system in which the turtle is represented as a view matrix. To orient the turtle glyph, which is essentially modeled in eye space but needs to be oriented in world space, I needed to apply the inverse of the view matrix.