The 3D Perspective Projection Process
The perspective projection process involves calculating what the 3D world would look like from the point of view (POV) of an arbitrary camera in 3D space. Perspective refers to the fact that more distant objects end up looking smaller, and to the mathematical fact that parallel lines in the 3D world may not end up looking parallel in the 2D perspective projection (i.e., the classic example of a road or a railroad track running off into the distance -- the tracks converge to a single point.)
Mathematically, perspective projection is a series of matrix transforms, summarized as follows:
- First, we define a camera in 3D space. Our camera is defined by the following parameters:
- The VRP, or View Reference Point, which is the location of the center of the view plane (the plane that the world is to be projected onto) in 3D space. (Think of it as the location of the camera in 3D space.)
- The VPN, or View Plane Normal, which is a 3D vector pointing in the direction that the camera is looking (conceptually, think of this vector as starting in space at the VRP and pointing towards the objects that we are looking at). This vector is defined to be normal to the view plane.
- The VUP, or View Up Vector, which is a vector pointing in the 'up' direction of the view plane. Together, the VRP, VPN, and VUP vectors let us define the view plane in 3D space.
- We also define d, the location on the VPN at which our center of projection is located. This is the negative direction, behind the VPN. Think of this as our focal length.
- We also need du and dv, which define the size of the view plane in world-coordinate lengths as measured from the VRP along it's x and y axes.
- To be able to do clipping, we need the F and B clip planes, which are simply the closest and farthest distances, respectively, from the VRP along the VPN that we can see.
- Finally, we need the actual screen size of the image that the camera should return, screenX and screenY.
- Now, in order to perform the perspective projection, we go through a series of steps. First, we move the VRP to the origin, so that the camera is now at (0,0).
- Now we want to make sure that our view plane is defined by three orthonormal vectors, so we normalize VPN and VUP and create a new vector UVEC defined as VUP cross VPN. Now we remake VUP as the cross product of VPN and the new UVEC, giving us three orthonormal axes, which lets us perform an axes alignment so that the view plane axes line up with (x, y, z).
- Now that the view plane is situated at the origin and it's axes match with (x, y, z), we can shift along the z axis so that the focal point is at the origin (shift by d).
- Now the world is situated so the origin is the focal point of our 'camera' and as we look in the z direction we see what the camera would see. We scale to what is called the CVV or Canonical View Volume, which is a cube with x running from -1 to 1, y running from -1 to 1, and z running from 0 to 1. This volume makes clipping easy (which we will add at a later point.)
- We're ready to do the actual projection! We project onto the image plane by applying a matrix transformation that scales the x and y values of a point by it's z value, thus making things farther away look smaller. (The matrix is simply [1 0 0 0; 0 1 0 0; 0 0 1 0; 0 0 1/d 0] where d is d/B.)
- That's it! Now we just scale to our desired image size using screenX and screenY and we're done! We draw it to the screen...and do whatever magical pixel shading, lighting, shadows, etc. we will need. Easy!
Extensions
Orthographic Projection: Parallel Projection
We did parallel projection by dropping the z coordinate instead of applying the perspective projection matrix. Here is an example. Notice how parallel lines are now straight, unlike in the example above.
Reminds me of drafting class from middle school!
|
Polygon and Point Lists
Looking ahead, it looks like being able to flatten a model into a list of points and polygons would be useful, so we have implemented that in this lab. Models can now render themselves, taking a vector of pointers to point3Ds and a list of polygonRef3Ds by reference and adding to the lists as needed. polygonRef3Ds are designed to reference their points from points in the point list, which will make polygon meshes, triangle strips, and triangle fans much more easy to work with, as, to avoid aliasing issues, they need polygons that can share points. Additionally, this system will make it easy to add alpha-buffering, as well as polygon meshes, triangle strips, triangle fans, and other such complicated surfaces and structures, in another lab.