Assignment 2 - 3D Shaded Surface Renderer

Due Wednesday Oct. 23, 2019 at 3:00 PM

pict

Overview

In this assignment, you will extend your code from Assignment 1 to write a program in C++ that reads in a description of a scene and rasterizes 3D shaded surfaces based on the objects in the scene as a PPM image output.

The graphics pipeline for this rasterization process is similar to the one that you implemented for the wireframe renderer. The difference is that we will be replacing Bresenham’s line drawing algorithm with new elements that allow rasterization of solid, colored triangles rather than simple skeletons of triangles. The new graphics pipeline still applies the same coordinate transformations from the previous pipeline (i.e. world space to camera space to normalized device coordinates), but it also makes use of interpolation via barycentric coordinates, surface normals, the lighting model, Gouraud and Phong shading, backface culling, and depth buffering to correctly color and shade all the triangular faces to obtain shaded surfaces. You will implement this entire pipeline in the assignment.

Before you begin, you may want to review the assignment material with these lecture notes. The files for this assignment can be downloaded here. More in-depth details for the assignment will be given in the sections below.


Your Assignment

As we said above, your task for this assignment is to implement the graphics pipeline for rendering scenes of shaded surfaces. The scenes for this assignment are described with an extension of the file format that you worked with in Assignment 1. Let us explain the additions to the file format with the following example file:

camera:  
position -2 0 5  
orientation 0 1 0 0  
near 1  
far 10  
left -0.5  
right 0.5  
top 0.5  
bottom -0.5  
 
light -0.8 0 1 , 1 1 0 , 0  
light 0.15 0.85 0.7 , 1 0 1 , 0  
light 0.5 -0.5 0.85 , 0 1 1 , 0.5  
 
objects:  
cube cube.obj  
 
cube  
ambient 0.2 0 0  
diffuse 0.8 0 0  
specular 0 0 0  
shininess 0.2  
s 1 1 1  
r 0 1 0 0.6  
t 0 0 0  
s 1 1 1  
r 1 0 0 0.75  
t -2.7 0 -2  
 
cube  
ambient 0.3 0 0.3  
diffuse 0.7 0 0.7  
specular 0 0 0  
shininess 0.2  
s 1 1 1  
r 0 1 0 -0.6  
t 0 0 0  
s 1 1 1  
r 1 0 0 0.75  
t -1 0 -3

The file format now specifies additional parameters:

In addition, the .obj files are now in a slightly different format to account for surface normals. Let us explain with the following example file:

v -1 -1 1  
v 1 -1 1  
v 1 1 1  
v -1 1 1  
v -1 -1 -1  
v 1 -1 -1  
v 1 1 -1  
v -1 1 -1  
vn 0 0 1  
vn 0 0 -1  
vn 0 1 0  
vn 0 -1 0  
vn 1 0 0  
vn -1 0 0  
f 1//1 2//1 3//1  
f 1//1 3//1 4//1  
f 6//2 5//2 7//2  
f 7//2 5//2 8//2  
f 2//5 6//5 3//5  
f 3//5 6//5 7//5  
f 5//6 4//6 8//6  
f 4//6 5//6 1//6  
f 4//3 3//3 8//3  
f 7//3 8//3 3//3  
f 1//4 5//4 2//4  
f 2//4 5//4 6//4

There are two main modifications to the .obj file format that you are used to seeing. The first is the presence of the vn lines. Just like how a v is followed by the x,y,z coordinates of a vertex in the object defined by the .obj file, a vn is followed by the x,y,z components of a surface normal of the object. Second, the f lines have been modified to include not only indices of vertices, but also indices of normals. Each a//b pairing specifies the index of a vertex as the integer a and the index of the surface normal for that vertex as the integer b. For instance, a line such as:

f 1//5 8//4 2//3

specifies a face composed of vertices 1, 8, and 2 with normals 5, 4, and 3 as the respective surface normals. Note that normal indices also start at 1, just like vertex indices. This is the standard .obj file format for defining objects with already computed surface normals.

Your task is to write a program in C++ that takes as input a file with the new scene format described above and outputs a PPM image of the specified scene (with desired x and y resolutions). The program should also have a “mode” argument, which can be either 0 or 1, and if it is 0, then the scene should be rendered with Gouraud shading; otherwise, the scene should be rendered with Phong shading.

The input of your program should be read from standard input as so:

./shaded_renderer [scene_description_file.txt] [xres] [yres] [mode]

xres and yres are integers that specify the x and y resolutions of the output image, and mode is either 0 or 1.

To help guide you, we have broken the task of writing this program into parts. We recommend that you read through all the parts carefully before you begin coding. Take some time to first plan out your code structure.

1.
(10 Points) Parse the scene description file and put the data into appropriate C++ data structures. Remember that the .obj file format has also changed!

2.
(5 Points) Just like in Assignment 1, create the transformation matrix for converting between world coordinates and camera coordinates; also create the perspective projection matrix. Then, for each object-copy in the scene, transform each of its points by all the geometric transformations that are to be applied to the object-copy.

Unlike in Assignment 1, you should not immediately convert all points to normalized device coordinates (NDC) since the lighting and shading algorithms still require world coordinates in addition to NDC. Recall that the conversions from world space to camera space and ultimately to NDC should happen within the shading or rasterization algorithms. We recommend writing a function to transform points from world space to NDC, and calling that function when necessary.

3.
(10 Points) For each object-copy, transform each of its surface normals by the correct normal transformations. Since your rotation and scaling matrices will most likely be 4x4 matrices, you may find it convenient to represent each normal n = (nx,ny,nz) as a 4x1 vector of (nx,ny,nz, 1) and simply multiply the 4x4 matrices with the 4x1 vector representations. Since you won’t be taking into account translations, the fourth rows and columns of your 4x4 transformation matrices here won’t have any effect. As a result, your resultant product vector will be of the form (nx,n y,n z, 1) with w = 1. Hence, you won’t need to worry about any sort of “homogeneous components” if you choose to do this.

Don’t forget to normalize your normals after you transform them! Remember that the lighting and shading algorithms assume unit normals.

4.
(20 Points) Implement the algorithm for the lighting model. Don’t forget to include attenuation!

5.
(25 Points) Implement the algorithm for rasterizing colored triangles with interpolation via barycentric coordinates, backface culling, and depth buffering.

You will probably want to use the same mapping for converting NDC into screen coordinates that you used in Assignment 1. You might also prefer to have the depth buffer as a global variable or as a member variable of your image data structure.

6.
(10 Points) Implement the full Gouraud shading algorithm using your lighting and triangle rasterization algorithms. Check whether the input mode is 0, and if so, call your Gouraud shading algorithm to rasterize each triangle of each object-copy to produce a scene of Gouraud shaded surfaces.

7.
(15 Points) Implement the full Phong shading algorithm (i.e. standard Phong shading with backface culling and depth buffering). Recall that the Phong shading algorithm is very similar in structure to the triangle rasterization algorithm. But rather than interpolating color across a triangle, Phong shading interpolates the vertex normals and world coordinates; and the lighting algorithm is called within the rasterization loop instead of before the loop. These few differences can actually make implementing Phong shading very different from implementing Gouraud shading, so take caution to plan out your code structure ahead of time!

Call your Phong shading algorithm when the input mode is 1 to rasterize each triangle of each object-copy to produce a scene of Phong shaded surfaces.

8.
(5 Points) Output the pixel grid to standard output as a .ppm image file.

Within the hw2 folder should be a folder called data. Inside the data folder are various scene description files in .txt format (plus the necessary .obj files) that you can use to test your program. The correct image outputs for each scene description file are also in the folder as 800x800 .png files. You can use these images to verify whether your program is working correctly.

Please do your work for this assignment in the hw2 folder of hw2.zip.


What to Submit

Before submitting, please comment your code clearly and appropriately, making sure to give details regarding any non-trivial parts of your program.

Submit a .zip or .tar.gz file containing all the files that we would need to compile, run, and test your program. In addition, please submit in the .zip or .tar.gz a README with instructions on how to compile and execute your program as well as any comments and information that you would like us to know.

We ask that you name your .zip or .tar.gz file lastname_firstname_hw2.zip or lastname_firstname_hw2.tar.gz respectively, where you replace the “firstname” and “lastname” fields with your actual first and last name.

Please submit your zip or tar.gz to moodle in the area for Assignment 2.


Written by Kevin (Kevli) Li (Class of 2016).
Links: Home Assignments Contacts Policies Resources