
       Projection Matrix and Perspective Division


In this renderer we rewrite the Camera and Projection classes so
that the projection operation makes use of a matrix multiplication.
This makes the renderer ready for more sophisticated changes in
future renderers.

When perspective projection is written as a matrix multiplication,
the matrix multiplication cannot in fact do the complete perspective
projection (perspective projection is a non-linear function, and a
matrix can only represent a linear function). After the matrix
multiplication, a new stage is needed called "perspective division".
In order to do the perspective division on a vertex, we add one new
method to the Vertex class.


All of our renderers so far have done perspective projection of a
point (x_c, y_c, z_c, 1) in camera coordinates using the set of
formulas
           x_p = -x_c / z_c,
           y_p = -y_c / z_c,
           z_p = -1.
These formulas cannot be turned (directly) into a matrix operation.
But just as translation was turned into a matrix operation by adding
a fourth coordinate to all our vertices, we can make perspective
projection into a matrix operation if we break up perspective projection
into two steps. The first step will be a (linear) matrix operation and the
second step, called "perspective division", will be a simple (non-linear)
formula.

Notice what the following 4-by-4 matrix does to a vertex in camera coordinates.

     [ 1  0  0  0 ]   [x_c]   [ x_c]
     [ 0  1  0  0 ] * [y_c] = [ y_c]
     [ 0  0  1  0 ]   [z_c]   [ z_c]
     [ 0  0 -1  0 ]   [ 1 ]   [-z_c]

Notice that the result vertex does not have its w-coordinate equal to 1.
Divide the result vertex by its last coordinate (that is, scale the
result vertex by the reciprocal of its w-coordinate, -1/z_c).

(-1/z_c) * [x_c, y_c, z_c, -z_c] = [-x_c/z_c, -y_c/z_c,  -1, 1]

                                 = [ x_p,      y_p,     z_p, 1]

Look carefully and notice how this matrix multiplication followed by a
scalar division gives us the exact same formulas we wrote above for the
perspective projection operation.

We will call the above matrix a "projection matrix", we will call
multiplication by this matrix a "projection transformation", and we
will call the scaling operation "perspective division". Notice that
this terminology is a bit messed up because multiplication by the
projection matrix is NOT really a projection transformation. The real
projection transformation is the matrix multiplication followed by the
perspective division. But this terminology is ubiquitous in computer
graphics.

The above matrix is not the only matrix that can be used to implement
a projection transformation. Consider the following matrix and what it
does to a vertex in camera coordinates.

     [ 1  0  0  0 ]   [x_c]   [ x_c]
     [ 0  1  0  0 ] * [y_c] = [ y_c]
     [ 0  0  0  0 ]   [z_c]   [  0 ]
     [ 0  0 -1  0 ]   [ 1 ]   [-z_c]

If we do perspective division on the result vertex,

(-1/z_c) * [x_c, y_c, 0, -z_c] = [-x_c/z_c, -y_c/z_c, 0, 1]

we once again recover the projection transformation formulas from our previous
renderers, but this time the projection is onto the plane z = 0 instead of the
plane z = -1.

Projecting onto the plane z = 0 or the plane z = -1 is not an important difference,
so either one of these matrices can be used to implement a matrix projection
transformation.


Now let us make orthographic projection into a matrix operation. This is
easy, since orthographic projection is in fact a linear transformation,
so it has a matrix. The formulas for the orthographic projection of a
point (x_c, y_c, z_c, 1) in camera coordinates are just
           x_p = x_c,
           y_p = y_c,
           z_p = -1.
The following 4-by-4 matrix does orthographic projection of a vertex in
camera coordinates onto the plane z = -1.

     [ 1  0  0  0 ]   [x_c]   [x_c]
     [ 0  1  0  0 ] * [y_c] = [y_c]
     [ 0  0  0 -1 ]   [z_c]   [-1 ]
     [ 0  0  0  1 ]   [ 1 ]   [ 1 ]

Notice that if this orthographic projection is followed by perspective division,
then the perspective division step doesn't really do anything (it divides by 1).
We will see in our code that when the renderer switches from perspective
projection to orthographic projection, it still does this (un-needed) perspective
division step.

The following matrix also does orthographic projection of a vertex in camera
coordinates. The difference is that this matrix projects onto the plane z = 0
instead of z = -1. This is not an important difference, so either matrix can
be used.

     [ 1  0  0  0 ]   [x_c]   [x_c]
     [ 0  1  0  0 ] * [y_c] = [y_c]
     [ 0  0  0  0 ]   [z_c]   [ 0 ]
     [ 0  0  0  1 ]   [ 1 ]   [ 1 ]


This renderer puts in the Camera class a reference to a projection transformation
matrix object. In our previous renderers, the Projection.java pipeline stage looked
in the Camera object to determine whether to do perspective or parallel projection.
In this renderer, the Projection.java pipeline stage will look in the Camera object
for a projection matrix. It will be up to the Camera object to store an appropriate
projection matrix (perspective or orthographic).


This renderer has one new file in the renderer folder
   PerspectiveDivision,
it has four new projection matrix classes in the scene folder
   OrthographicProjectionMatrix.java,
   PerspectiveProjectionMatrix1.java,
   PerspectiveProjectionMatrix2.java,
   PerspectiveProjectionMatrix3.java,
and it modifies the files
   Camera.java,
   Vertex.java,
   Project.java,
   Renderer.java.
The client programs have been changed so that you can cycle through the different
perspective projection matrices.


There are three new client programs,
   SomethingWrong1.java
   SomethingWrong2.java
   SomethingWrong3.java
that demonstrate some ways in which our renderer is not rendering properly.
These problems will be fixed in future renderers.


Our fourth pipeline has the following six stages.


        v0      v1      A LineSegment object
         \     /
           \ /
            |
            | model coordinates (of v0 and v1)
            |
        +-------+
        |       |
        |   P1  |    Model-to-camera transformation (of the vertices)
        |       |
        +-------+
            |
            | camera coordinates (of v0 and v1)
            |
        +-------+
        |       |
        |   P2  |    Projection transformation (of the vertices)
        |       |
        +-------+
            |
            |
           / \
         /     \
       /    P3   \   Perspective division (of the vertices)
       \         /
         \     /
           \ /
            |
            |
           / \
         /     \
       /    P4   \   Clipping (of the line segment)
       \         /
         \     /
           \ /
            |
            |
        +-------+
        |       |
        |   P5  |    Viewport transformation (of the vertices)
        |       |
        +-------+
            |
            | viewport coordinates (of v0 and v1)
            |
           / \
         /     \
       /    P6   \   Rasterization (of the line segment)
       \         /
         \     /
           \ /
            |
            |  pixels (for this line segment)
            |
           \|/
        FrameBuffer
