CS40: Computer Graphics, Lab 6

Perspective Projection

By Jeff Kaufman

In this lab I extended the graphics library I started in lab 2 by adding support for perspective projections.

Mathematics

The task is conceptually pretty simple. We need to take the world and align it with the viewer. At this point drawing the scene as if it were 2D and ignoring the Z values would result in a parallel projection: one where parallel lines are drawn as parallel on the screen. This is not, however, the way a person percieves the world; we have perspective. For a scene to be realistic, more distant objects need to be relatively smaller. This means that two lines that are always a meter apart need to have fewer pixels between them as they get farther away.

The first transformation we can do with a matrix. It's simply a matter multiplying every point in the world by a translation matrix generated from the inverse of the viewer's location. The rotation of the world to align with the orientation of the viewer can be done by taking advantage of a useful result from linear algebra, which tells us how to simply make a matrix from three mutually orthoganal unit vectors which will align each of those unit vectors with one of the three axies, bringing the rest of the world along with it.

While it is not necessary for this projection, it is useful to scale everything visible to be within a unit cube, the cannonical view volume. When all points are in this coordinate system, clipping becomes both simple and fast. Getting the points into this coordinate system is a matter of multiplying them by appropriate scale and translate matricies.

To add perspective we cannot use only matricies. We would need a single matrix that could be used on all points and would modify each point's x and y coordinates on the basis of their z coordinate. What we can do instead is modify the fourth or homogeneous coordinate of our points with a matrix and then later, when it comes time to draw the point or the structure containing that point, divide the x and y coordinates by the homogeneous coordinate.

All of these manipulations are matrix manipulations, with the exception of part of the perspective calculation, and they can (almost) all be combined into one matrix by which every point is multipled. This is pretty efficient, as we need calculate only one matrix and need do only on matrix-vector multiplication for each point. In hardware this would be better, as matrix multiplications parallelize well.

Required Images

Two unit cubes (at [ 0.5, 0.5, 0.5 ]), straight on (from [ 0.5, 0.5, -2 ]) and in three point perspective (from [ -1.7, 1.2, -3 ]):
The second cube looks pretty bad; some lines are off by a pixel. This is not a problem with the perspective calculations, but instead with my implementation of Bresenham's line drawing algorithm.

Lab Questions

  1. The world space (x,y,z) values for the corners of the unit cube are: The calculated values in screen space (x,y) for the corners in the first image were: The calculated values in screen space (x,y) for the corners in the second image were:
  2. The distance between the center of projection (COP) and the view reference point (VRP) is in our system represented by the parameter d. With d at 2, we get the reference images above. The images below have d as 1 and 4 respectively.
    the cube viewed with a d of 1 the cube viewed with a d of 4
    The most obvious change is that the cube looks smaller with smaller values of d and larger with larger ones. But the screen space length of the lines going into the screen remained the same, so we're not simply moving closer or farther from the image, as the pictures below do:
    the cube viewed from 4 away the cube viewed from 1 away
    What this illustrates is that changing position and changing zoom level are not the same thing, and d controls the zoom level.
  3. The VUP vector indicates which direction is up for the camera. Moving the VUP vector between vertical and horizontal makes the cube appear to rotate:
    the cube viewed with a varying vup
  4. Changing the view window squishes or stretches the image. The two images below are again of the same cube, but this time with the view window half and twice as wide as before:
    the cube with a 50x100 (narrow) view window the cube with a 200x100 (wide) view window
  5. I did not do many extentions to this lab. I wrote a function for adding cubes:
    Module_addLineCube(Module* md, double center_x, double center_y, double center_z, double radius);
    with an accompanying command wirecube x y z : radius for the module file format. I also wrote a function for adding spheres:
    Module_addLineSphere(Module* md, double center_x, double center_y, double center_z, double radius, double resoltion);
    with an accompanying file format command command wiresphere x y z : radius : resolution. This sphere is made by starting with a tetrahedron and recursively breaking the lines at their midpoints, pushing these midpoints out to the surface of the sphere, and connecting the midpoints to make new lines. The resolution argument indicates how many breaks to make. The images below, with links to movies, show the sphere approximations for resolution values of 1 through 5.
    Iteration 1 Iteration 2 Iteration 3 Iteration 4 Iteration 5
    There are many extra lines used in this method because of the relative ordering of the recursion and the line drawing. They are not visible because they are exact duplicates, but they are slowing. I implemented the sphere this way so once I implement Z-buffering I can modify it simply to draw solid spheres.


Jeff Kaufman : 2006
cbr at sccs dot swarthmore dot spam edu. Remove spam.

main page