Program 1 - Software Rasterization of Triangle Meshes

GitHub Classroom Assignment Page

The base code for this lab can be found on GitHub here

This assignment is due on Monday 1/22.

This is an individual project.

Goal:

Create a program that reads in and renders an indexed face set meshes (of type .obj) to an image via software rasterization. You may use existing resources to load in the mesh and to write out an image. You must write your own rasterizer. In general the required steps for the program are:

Task 1:

Download the base code, which has a mesh loader and an image writer from github.

The mesh loader is an obj loader and the image writer is the same as the one used in prior labs.

Example mesh files are included in the base code, and you can create your own to represent a single triangle, etc. In addition, there are numerous OBJ meshes on the web. For grading purposes, your program will be run using the provided Stanford Bunny and Utah Teapot.

Ultimately you will want each triangle to be represented in a C/C++ structure/class, with 3 vertices and a color per vertex. In addition, your triangle data should include a 2D bounding box, which will represent the triangle’s extents in window coordinates.

Task 2:

Add a command line argument to accept the following command line arguments.

For example, your program should be able to be run as follows:

./raster ../resources/bunny.obj out.png 512 512 1

Add error checking to specify the required command line arguments if an incorrect number are given – and include an example correct command line run. Your program should not dump core if no input file is specified, nor fail without an error message! Follow the golden rule, treat your user/grader/instructor the way you’d like to be treated as a user/grader/instructor.

Task 3:

Write code to convert each 3D coordinate into 2D window coordinates. Assume the camera is at the origin looking down negative z. Make sure the object completely fills the image.

Some tips for starting out:

Write out the bounding box, rather than the triangles, to the image. If you do this with the provided sphere, teapot, and bunny, you should see blocky images like below. Make sure the object looks reasonable in terms of scale and shape.

program1_1.png
program1_2.png
program1_3.png

Once the bounding boxes are being displayed correctly, you can add the barycentric test to write out the triangles as in Lab02. You should not see any gap between the triangles.

program1_4.png
program1_5.png
program1_6.png

Make sure you test nonuniform window sizes. As show below, the aspect ratio of the object should be preserved no matter what the image size is, and the object should be reasonably scaled.

program1_7.png
program1_8.png

Task 4:

The triangles of the objects are in a certain order.

From a certain viewpoint, some triangles might not be visible due to other triangles being in front of them (relative to the camera). This is called occlusion.

You won’t notice any problems with this if your triangles are all the same color (as above).

Coloring

Incorporate your lab code to rasterize a triangle with a color defined per vertex. Any point within the triangle should be drawn with colors interpolated via the barycentric coordinates. Likewise, z (depth) should also be interpolated using the barycentric coordinates and written to the z-buffer.

Use the z value of the vertices as the color. (You can choose any color, not just red.) To do this, you have to map the z-value to the range 0 to 255.

You may immediately notice weird results in your render.

program1_9.png

This is because some triangles should be occluded by others, but whichever triangle is rendered last is the one that actually shows up in front.

We can resolve this using a z-buffer.

Z-Buffer

Create a data structure to support z-buffer tests. Your z-buffer should be a separate buffer from your image pixel buffer, and it should be the same size as your pixel buffer.

For testing if a pixel is in the foreground, you need to compare the z-buffer value on the position of the new pixel:

If there is none, write the new pixel color and z value.
If its less (farther away) than the new z value, write the new pixel color and z value.
If its more (closer), do not overwrite the pixel or z value.

program1_10.png

Task 5

Use the “color mode” command line argument to switch between two modes. If mode is 1, then use the z-value as in the previous task. If mode is 2, then use the y-value to linearly interpolate two colors of your choice. For example, in the right figure below, I am interpolating between yellow and cyan. Make sure to specify these two colors in your README. The color should vary smoothly from top to bottom.

depth teapot
colored teapot
colored bunny

Important Note

Make sure to pass your std::vector by reference rather than by value.

void foo(std::vector<float> & bar)

Here, the & means the argument is passed by reference, not copy.

Otherwise, your program may become too slow.

And a note about graphics “bugs” - cut and paste errors are SO easy to introduce to your code, with three coordinates and three colors, etc. Be sure to re-read your code. Probably 75% of all broken student code I read has an “x” where there should be a “z” or similar. The up side in “bugs” sometimes look cool. A cut and paste bug that made this cool effect in gradient code…

broken bunny

Read your code!

Point breakdown

Total: 100 points

What to hand in

Failing to follow these points may decrease your “general execution” score. Make sure that your code compiles and runs by typing, for example:

> mkdir build
> cd build
> cmake ..
> make
> ./raster <ARGUMENTS>

Make sure the arguments are exactly as specified. Include a README file that includes:

Make sure you don’t get any compiler warnings. Remove unnecessary debug printouts. Remove unnecessary debug code that has been commented out.

Do not commit anything in the build/ directory, the executable, input obj files, output image files, old save files (*.~), or object files (*.o).