Due midnight 12 November 2008 (Wednesday night)
For this assignment you'll implement z-buffer rendering to do hidden surface removal.
This week you need to implement all of the z-buffer functions we've skipped so far. Several of the z-buffer functions are part of the Image functions in section 2. In particular, you'll need to make sure a z-buffer is allocated and initialized when you initialize an image. Then you'll need to modify your scanline fill algorithm to make use of the z-buffer. The graphics specification is the same as for last week.
The major steps are outlined below.
- Modify your Image structure to include a z-buffer.
- Modify your Line, Polygon, and Polyline structures to include a z-buffer flag (if they don't already), and implement the functions that let a programmer set the flag.
Create a Z-buffer-fill algorithm from your scanline-fill algorithm.
In the makeEdgeRec function, use the depth values at each end of an edge to calculate a zIntersect and a dzPerScanline value. Just like the xIntersect value in the scanline-fill, the zIntersect value needs to be incremented by dzPerScanline each time you move up a row (in the UpdateActiveList function). Inside of the fillScan function, you will need to compute a dzPerColumn value to increment the z-value across a scanline. Don't forget to use 1/z in all of your calculations.
Using linear interpolation, you should be able to calculate a depth at each pixel location. You can test your algorithm by writing out a picture of a polygon, like a triangle, and scaling the intensity of the image based on depth (the further away, the darker it gets).
As noted in class, under perspective projection, z values do not interpolate linearly in x and y. However, 1/z does interpolate linearly in x and y. So you will want to make your zIntersect, dzPerScanline, and dzPerColumn values reflect the inverse z values. Note that you do not have to execute an inversion to get the true z value in order to do hidden surface removal. Instead of testing whether the z value of a polygon is less than the current z value at a pixel, just test whether the 1/z value of a polygon is greater than the current 1/z value at a pixel (so store 1/z values in your depth map and initialize your depth map to 0 (infinite distance) or 1/B, which is 1.0 in canonical view coordinates).
Be sure to initialize your z-buffer in the Image structure to the appropriate background values when you create it. Furthermore, if you are creating multiple images, you may want to add a function that lets you clear the z-buffer as well as the image color values.
Finally, within the FillScan() routine of the scanline-fill algorithm, you need to add the Z-buffer logic that compares the current depth value of a polygon pixel with the value in the Z-buffer for that pixel. If the polygon's depth is closer (1/z is greater), write the pixel to the image and update the Z-buffer. If the new value is further away (1/z smaller), don't modify the image or the Z-buffer.
Note that you may want to pass around a pointer to the polygon structure in functions like MakeEdgeRec in order to test whether to use the z-buffer or not.
Modify your line drawing function so that it also uses the z-buffer
when drawing. Note that you probably want to make a whole separate
line drawing function that is called if the z-buffer flag is set,
rather than trying to put lots of if-statements in your existing
line code. The the Line_draw() function just decides with of the
procedures to call based on the flag.
- Run the example program cubism.c. For the image sequence shown below I modified the colors of the polygons based on depth in order to show the zbuffer was working. I highly recommend doing that as a debugging tool. Just looking at z-values as numbers is not helpful.
- Make an example that would be a useful demonstration of the z-buffer concept.
- Build a full scanline rendering system that executes all polygons in one pass.
- Build an A-buffer system instead of a z-buffer system so you can do transparency (and shadows).
- Make interesting models, like planets and spheres.
- Make cool pictures and animation sequences.
- Handle aliasing issues at boundaries by using the centroid value of polygons to determine which of two polygons of similar depth is really in front.
All writeups should suggest the format of a lab report. They do not have to be long, but need to provide enough information that I have some idea you knew what you were doing.
- Abstract: 200 word description (at most) of what you did and a picture to go along with it.
- Description of the task, in your own words. Be brief, but write it as though explaining it to a fellow student not in the course.
- Description of how you solved the task, including any key equations or algorithms. You should also include algorithms or descriptions of what you did for any extensions. Include pictures here.
- More pictures. Please put a caption on each picture explaining something about it. If you have nothing else, give it a name and indicate whose picture it is.
- Summary of what you learned.
Put your code files in your handin folder. Send the prof an email with the URL for your writeup (wiki or standard web page) when it's done. In either case, please edit the assignment handin page on the wiki so there is a link to your assignment.