up to Schedule & Notes

The Projection Matrix

$$ \def\pocs{p_\textrm{ocs}} \def\pwcs{p_\textrm{wcs}} \def\pvcs{p_\textrm{vcs}} \def\pccs{p_\textrm{ccs}} \def\pndcs{p_\textrm{ndcs}} \def\pdcs{p_\textrm{dcs}} \def\Oocs{O_\textrm{ocs}} \def\Owcs{O_\textrm{wcs}} \def\lh{-\hspace{-0.2in}} \def\rh{\hspace{-0.2in}-} $$

The Projection Transform looks like this:

$\pccs = \begin{bmatrix} E & 0 & A & 0 \\ 0 & F & B & 0 \\ 0 & 0 & C & D \\ 0 & 0 & -1 & 0 \\ \end{bmatrix} \; \pvcs$

Let $\pvcs = (x, y, z, 1)$ and let $\pccs = (x', y', z', w')$. Then

$\begin{bmatrix} x' \\ y' \\ z' \\ w' \end{bmatrix} = \begin{bmatrix} E & 0 & A & 0 \\ 0 & F & B & 0 \\ 0 & 0 & C & D \\ 0 & 0 & -1 & 0 \\ \end{bmatrix} \begin{bmatrix} x \\ y \\ z \\ 1 \end{bmatrix}$

How $y'$ is Calculated

From the transformation matrix above, $y' = F y + B z$. Consider a 2D slice at $x = 0$ through the view volume (shown on the left below) and the corresponding 2D slice at ${x' \over w'} = 0$ through the canonical view volume (shown on the right below):

Points on the top line of the view volume satisfy ${y \over -z} = {t \over n}$. That is, there points are of the form $({-tz \over n} , z)$. These points correspond to points on the top line of the canonical view volume that satisfy ${y' \over w'} = 1$.

Substitute a point $({-tz \over n} , z)$ into the $y'$ and $w'$ lines of the transformation matrix:

$\begin{array}{rl} y' & = F y + B z \\ & = F {-tz \over n} + Bz \\ w' & = -z \end{array}$

As stated above, the VCS point $({-tz \over n} , z)$ is transformed to a CCS point for which ${y' \over w'} = 1$. So

$\begin{array}{rl} {y' \over w'} & = { {F { -tz \over n} + Bz } \over -z } & = {t \over n} F - B & = 1 \end{array}$

So we know that

${t \over n} F - B = 1$.

By a similar argument (using VCS points $( {-b z \over n}, z )$ on the bottom line which map to CCS points for which ${y' \over w'} = -1$) we can show that

${b \over n} F - B = -1$.

We can then solve the two equations in $F$ and $B$ to get:

$\begin{array}{rl} F & = {2 n \over t-b} \\ B & = {t+b \over t-b} \end{array}$

How $x'$ is Calculated

This is done analagously to $y'$.

Given $\ell$ and $r$ which are the left and right limits in the $x$ direction of the view volume, we apply the same method as for $y'$ and get

$\begin{array}{rl} E & = {2 n \over r-l} \\ A & = {r+l \over r-l} \end{array}$

How $z'$ is Calculated

VCS points on the near plane ( $z = -n$ ) map to CCS points on the line ${z' \over w'} = -1$, and VCS points on the far plane ( $z = -f$ ) map to CCS points on the line ${z' \over w'} = +1$.

From the transformation matrix:

$\begin{array}{rl} z' & = C z + D \\ w' & = -z \end{array}$

Substitute $z = -n$ to get one equation. Substitute $z = -f$ to get another equations. The unknowns are $C$ and $D$:

$\begin{array}{rl} {z' \over w'} & = {{C (-n) + D} \over n} \\ & = -C + {D \over n} \\ & = -1 \\ \\ {z' \over w'} & = {{C (-f) + D} \over f} \\ & = -C + {D \over f} \\ & = +1 \end{array}$

Solving the equations yields:

$\begin{array}{rl} C & = {f+n \over n-f} \\ D & = {2fn \over n-f} \end{array}$

The VCS-to-CCS Transformation Matrix

Bringing everything together:

$\pccs = \begin{bmatrix} {2n \over r-l} & 0 & {r+l \over r-l} & 0 \\ 0 & {2n \over t-b} & {t+b \over t-b} & 0 \\ 0 & 0 & {f+n \over n-f} & {2fn \over n-f} \\ 0 & 0 & -1 & 0 \end{bmatrix} \; \pvcs$

Other VCS-to-CCS transformation matrices exist. In particular, orthographic projection is sometimes used.

See functions frustum(), perspective(), and ortho() in 00-intro/src/linalg.cpp in openGL.zip.

Clipping in the CCS

Points outside the view frustum must be clipped. The clipping could be done in almost any coordinate system, but it's best to do clipping in the CCS because:

  1. The canonical view volume in the CCS is independent of camera parameters. That means that clipping in the CCS can be implemented in hardware which doesn't have to be parameterized ... so it's fast. There's no point earlier in the sequence of transformations where clipping can be done in a camera-independent manner.
  2. After the perspective division (CCS-to-NDCS) some depth information is lost, which can result in improper clipping (as discussed below). So it doesn't make sense to clip after the CCS.

Example of Improper Clipping in the NDCS

In the figure below, the segment $pq$ in the VCS is transformed to the segment $p'q'$ in the NDCS. If we clip $p'q'$, the segment will appear to be exiting the far plane of the canonical view volume. But it should really exit the top plane!

For example, if $q = [0,0,-100,1]^T$ and $n=1, f=2, r=+1, l=-1, t=+1, b=-1$ then $q$ is behind the viewpoint (as above) and the projection matrix is

$\left[\begin{array}{cccc} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & -3 & -4 \\ 0 & 0 & -1 & 0 \end{array}\right]$

Then $q' = P q = [x', y', z', w']^T = [0, 0, -304, -100]^T$ and, upon division by $w'$ we get $[0, 0, 3.04]^T$, which is ahead of the viewer instead of behind, as the original $q$ was.

For a better intuition, consider what happens to $q'$ as $q$ is moved along the $z$ axis of the VCS:

Proper Clipping in the CCS

If the point were in NDCS, we would clip against the six planes that define the faces of the canonical view volume:

$\begin{array}{rcr} {x' \over w'} = +1 & \qquad & {x' \over w'} = -1 \\ {y' \over w'} = +1 & & {y' \over w'} = -1 \\ {z' \over w'} = +1 & & {z' \over w'} = -1 \end{array}$

The corresponding planes in the CCS are:

$\begin{array}{rcr} x' - w' = 0 & \quad & x' + w' = 0 \\ y' - w' = 0 & & y' + w' = 0 \\ z' - w' = 0 & & z' + w' = 0 \end{array}$

Given a segment $p'q'$ in the CCS, we clip against each of the six planes. Note that these are planes in a 4D homogeneous space, but clipping works the same in any dimension, as we'll see below.

Clipping a Segment Against a Plane

A line segment $ab$ has endpoints $a$ and $b$. It can be written in parametric form as

$\ell(t) = a+t(b-a)$

For $t \in [0,1]$, $\ell(t)$ is between $a$ and $b$. For $t$ outside this interval, $\ell(t)$ is not on the segment $ab$.

A plane $\pi$ is defined by a normal, $n$, and a distance from the origin, $d$. All points $x$ on the plane satisfy the implicit equation

$\pi(x) = n \cdot x - d = 0$

Points above the plane (i.e. on the side of the plane that $n$ points to) will have $\pi(x) > 0$. Points below the plane will have $\pi(x) < 0$.

Segment $ab$ is clipped by the plane if and only if its endpoints lie on different sides of the plane. So compute $\pi(a)$ and $\pi(b)$. Then $ab$ intesects $\pi$ if and only if $\pi(a)$ and $\pi(b)$ have different signs. (If one or both are equal to zero, $ab$ is not clipped because it does not cross the plane.)

If $ab$ is clipped by $\pi$, we need to find the point at which $ab$ intersects $\pi$, to clip $ab$ at that point.

To find the point of intersection, substitute the parametric segment equation into the implicit plane equation and solve for the parameter $t$:

$\begin{array}{l} 0 = \pi( \ell(t) ) \\ 0 = \pi( a+t(b-a) ) \\ 0 = n \cdot (a+t(b-a)) - d \\ t = { \large d - n \; \cdot \; a \over \large n \; \cdot \; (b-a) } \end{array}$

Then the intersection point is $\ell(t)$.

up to Schedule & Notes