Project3SP15
Contents |
Project 3: Software Rasterizer
In this project you will need to write your own software rasterizer. We provide some code that will allow you to integrate your rasterizer with OpenGL.
The project is due on Friday, April 17th, 2015 at 1pm. You need to present your results in the CSE basement labs as usual, grading starts at 12:15pm.
The homework discussion for this project will be on Monday, April 13th.
Getting started
We provide base code for you which displays a software frame buffer on the screen. Your task is to rasterize your scene into this frame buffer. In this assignment you are not allowed to use any OpenGL calls which aren't already in the base code. Instead, use your vector and matrix classes from assignment #1 and add your own rasterization routines.
1. Rasterize Vertices (20 Points)
In the first step of building your own rasterizer you need to project the vertices of the 3D models from assignment 2 to the correct locations in the output image (frame buffer).
You should use the same model, camera and projection matrices as in assignment 2, so that you can use the rendering results from it to verify that your software rasterizer works correctly. We recommend that you start with your code from assignment 2 and copy-paste code from rasterizer.cpp where you need it.
Add support for the 'e' key to switch between your rendering engines: OpenGL from the previous assignment and your new software rasterizer. When in software rendering mode, use the - (minus) and + (plus) keys to go back and forth between the different parts of this homework project, which all build upon another.
Add a viewport matrix (D) to your code, and implement a method to create D based on the window size (window_width and window_height) and call it from the GLUT reshape function. Your program must correctly adjust projection and viewport matrix, as well as frame buffer size when the user changes the window size, just like in your previous assignment.
Then write a method to rasterize a vertex. You can use drawPoint from the base code to set the values in the frame buffer. Call this method from the draw callback (display function in base code) for every vertex in the 3D model. For this part of the assignment, create a method rasterizeVertex which projects each vertex of the house to image coordinates. At this stage, render every point in bright white.
Grading:
- -5 if rasterized image doesn't resize the same way as in OpenGL mode
- -10 if rasterized image doesn't respond to keyboard keys
- -5 if not all 3 models load
- -10 if vertex positions wrap around when off screen
- -5 if bounding box is not fully traversed (leaving blank lines)
2. Rasterize Triangles (40 Points)
Now you will need to render the objects' triangles instead of just the vertices. Use the Barycentric interpolation algorithm to determine whether a framebuffer pixel is inside or outside of the triangle you are rasterizing. To do this you should first compute a bounding box around the triangle, limited to the extent of the triangle, then step through all pixels in the bounding box and test if they lie within the triangle by computing their barycentric coordinates. Pick a random color for each triangle and use it throughout the triangle.
Notice that because you are not depth sorting the triangles, some of the foreground triangles might get overwritten by background triangles - we will fix this in the next step.
Grading: The same deductions apply as in part 1 if not already deducted there.
3. Z-Buffer (25 Points)
So far the triangles are rendered in the order in which they are listed in the file. Triangles rendered later will overwrite those that were rendered earlier. This approach causes problems with occlusion.
The remedy is to implement the z-buffer algorithm. Linearly interpolate z/w for every point using the Barycentric interpolation weights and scale it to the range of 0 to 1, between the near and far planes. The result is the z-value, which you need to compare with the previously stored z-buffer value for this pixel. Make sure that you clear the z-buffer (initialize with 1) whenever you clear the frame buffer.
Grading:
- -10 if z-buffer indices are incorrectly calculated
- -5 if z-buffer is not initialized correctly for every frame
- -5 if z-buffer does not resize correctly on window resizes
4. Per Pixel Colors (15 Points)
While triangle overlaps are now correctly resolved, the triangles look very boring. When rasterizing a triangle, change out the random color to a per pixel shading algorithm: use barycentric interpolation to interpolate the vertices' normal vectors within the triangle. Then color each pixel by interpreting the normal at it as an RGB color: the x component determines the amount of red, y determines green, z for blue. Note that the x/y/z values range between -1 and +1, so to map them to colors you'll have to add one and divide by two, to bring them into the desired range of 0 to 1.
Grading:
- -10 if colors are not interpolated across triangles
5. Extra Credit: Translucent Spheres (10 Points)
Build a scene out of two spheres, with one spinning around the other, rotating around the Y axis, so that one sphere is sometimes in front and sometimes behind the other sphere. The spheres should never intersect.
Make both spheres translucent by mapping an opacity value (=alpha value) of roughly 50% (or 0.5 on a scale between 0 and 1) to all triangles.
Render the overlapping spheres correctly, as if they were made out of translucent glass: to do that the triangles need to be rendered in back-to-front order. To accomplish this you will need to sort all triangles of both spheres from back to front (based on their distance from the camera), every time you render a frame. To sort the triangles, calculate the center point of each triangle, project it into camera coordinates, and use the resulting z value as the sorting criterion.