15-462 Computer Graphics Spring 2004

Programming Assignment #3 - Ray Tracing

Due Tuesday, November 16 at midnight




In this assignment, you will be building a ray tracer. As already discussed in lecture, ray tracing is a powerful method to perform global illumination. Ray tracers are widely used to render photorealistic images and animations. Examples of globally illuminated renders of a Cornell Box (some ray traced) can be found at Henrik Wann Jensen’s page here. Also, you might want to take a look at the Internet Ray Tracing Competition for inspiration.


At the end of this assignment, your ray tracer should be able to minimally handle opaque surfaces with lighting, shadows, reflections and texture mapping. Provided for you will be some starter code that performs some elementary parsing functions.


Sending out rays


The first step is to uniformly send out rays from the camera location. You will need to use backwards ray tracing where rays are sent from the camera, one ray per pixel. We would recommend the final images be 640x480, but for debugging purposes you would see faster rendering times for fewer rays. For example, halving each dimension of your image would cause only 1/4th of the rays to be sent out.


When generating your rays, use a perspective projection "camera" with the image plane centered at z=-1 with the y-axis as up. Place the eye point at the origin and bound the image plane at x=[-1/2, 1/2], y=[-3/8, 3/8]. This will allow us to standardize images for testing.


There are a number of ways to store the data generated from ray tracing. One way is to directly output each pixel to the screen as it is generated. If you do a flush and swap buffers, you can watch the scene being rendered. The disadvantage is that this may be a slow way to render; a speed up may be to write the data to the display every line, instead of every pixel. Another way to render is to store the data in an off-screen buffer, and send the whole data to the video buffer. This may be faster, as accessing the video buffer directly may be slow. To write to the video buffer, you should use the function glWritePixels()(on the command line, man glWritePixels for more information). The PIC_PIXELS macro can be used for JPEG writing. You could use the PIC_PIXELS macro to not deal with the OpenGL at all. Just allocate memory for a JPEG file, and use the PIC_PIXELS macro. You should be able to look at some of the provided functions to perform pixel plots in rt_start.C. 


Intersection Testing


The next step would be to write code for intersections and texture mapping. The mathematical solutions for the intersection and texture mapping code are provided in the lecture notes and handouts.


In order to perform Phong shading, normals are required. For triangles, you can interpolate the x, y, and z coordinates of the normals at each vertex, and then normalize the length. We recommend using barycentric coordinates for interpolation of triangles. For spheres, the normal is simple to calculate from the center of the sphere.


You are also required to implement texture mapping. For triangles, this is very similar to interpolating normals. For spheres, we recommend using spherical coordinates for texture mapping.




The third step in the process would be to implement the illumination equations. The illumination equation for a surface point is given by:


I = (ka * Ia) + Ii * (kd * (L.N) + ks * (R.V)^n)


The slight modification we suggest you use is as follows:


ka = kd (the ambient material term is the same as the diffuse material term).


For rays with a non-zero specular component, you need to recurse (upto a maximum depth of at least 3). To add in the value of this recursive ray, use the following formula:


Ifinal = I + ks * Ir


Class Design & Structure


The design and the structure for the various classes has been left up to you. At the very least, the classes you implement must support the constructors that are called from the rt_parse.cpp file for the parser to compile properly. You should read through this file and start working out your class design before writing any code. We have provided an example class hierarchy, but you may change the hierarchy (or substitute your own) in your implementation. You are encouraged to take full advantage of C++ object oriented programming features.  You can find additional information on the parser design and the starter code skeleton in the doc/html directory of the starter code (start at index.html).


You are allowed to modify the parser (or use another programming language), but be certain that the parser in your solution is able to read and process (at minimum) the simple scene description format that is described below.


Simple Scene Description Format


The (informal) grammar for the simple scene description format is as follows:


symbol key: * means "zero or more," ? means "zero or one," ( and ) are grouping symbols and are not actual parts of the grammar


# The Simple Scene Description Language allows for comments in the file. All

# characters between a # token and the end of the line are ignored


scene :: = background lights materials group


background ::= Background {

                          color Vec3f

                          ambientLight Vec3f



lights ::= Lights {

                   light *



light ::= Light {

                          position Vec3f

                          color Vec3f

                          ( attenuation float float float )?



materials ::= Materials {

                   material *



material ::= Material {

                   textureFilename string

                   diffuseColor Vec3f

                   specularColor Vec3f

                   shininess float

                   ( transparentColor Vec3f )?

                   ( reflectiveColor Vec3f )?

                   ( indexOfRefraction float ) ?



group ::= Group {

               object *



object ::= sphere | triangle


sphere ::= Sphere {

               materialIndex int

              center Vec3f

              radius float



triangle ::= Triangle {

                   vertex0 Vec3f

                    normal_vertex0 Vec3f

                    materialIndex0 int

                    s_t_tex_0 float float

                   vertex1 Vec3f

                    normal_vertex1 Vec3f

                    materialIndex1 int

                    s_t_tex_1 float float

                   vertex2 Vec3f

                    normal_vertex2 Vec3f

                    materialIndex2 int

                    s_t_tex_2 float float



Vec3f ::= float float float


Texture coordinates are given in standard order (x,y). Attenuation coefficients are in terms of the attenuation equation a + bx + cx^2.


For triangle texture mapping, you may use the texture assigned to the material at vertex 0 as the texture for the entire triangle.


A small example of a test scene with all the above elements can be found here. Note that the parser requires the scene to have an extension of .ray.


Creating Test Scenes





Sharing Test Scenes with the class


You're all encouraged to share test scenes with each other in a public forum - in this case, the course bboard, at cmu.cs.class.cs462. Post the scene file itself, along with a picture of what your ray tracer produced with it - this should help everyone debug their ray tracers in a collaborative manner. If anyone would like to share their scenes but would like to do so anonymously, send your scene and picture to mtomczak@andrew.cmu.edu, and it'll be posted for you onto the bboard. If you use anyone’s test scenes in debugging and/or improving your ray tracer, please acknowledge with the appropriate credit in your README file.


Think before you hack!


Past iterations of the course and of this assignment have shown us that many students rush into implementing their ray tracers without giving much thought to the design and architecture of their solution. We strongly encourage you to plan out the pieces of your ray tracer coherently before you get started on writing any code. Furthermore, this will give you a good opportunity to clear up any lingering doubts you might have about the assignment itself before getting started with the implementation. Be warned - there will be very little OpenGL programming in this assignment.


You will notice that the starter code provided is in C++. Ray tracers lend themselves to naturally elegant object-oriented solutions, and by using such an environment, we hope to get you to think about your design a lot more than in prior assignments. Students may wish to use Java or ML - you are welcome to try, but we must enforce the constraint that your submission must run on the machines in the graphics cluster. If you wish to use Java or ML to complete this assignment, make sure to talk to Professor Pollard or one of the TA's before you begin.


Functionality Requirements


This is the list of requirements for this assignment.



The above list constitutes 130 points of the 150 point assignment. For the other 20 points, and up to 30 points possible extra credit, you may choose features to implement from the following list.



There are many more possible extensions to your ray tracer – please contact the course staff if you’re curious about how much your extension is worth. Make sure that scenes you come up with show off your extra credit features as much as possible.


Animation or Still


In addition to your program, you are also required to hand in an animation or still picture in the form of JPEG files.


The animation or still should be something that shows off your features. For example, if you implemented a spatial partition, your scene could be more complicated. The animation should consist of a series of JPEGs stored in a subdirectory called movie/.


If you do a still, please create a directory called movie/ and place 60 copies of your still, numbered 000.jpg to 059.jpg. We will run the frames at 15 fps.


For a movie, the JPEGs should be numbered consecutively starting from 000.jpg.


Handin Instructions


Handin for this assignment is exactly the same as previous assignments – copy all your code (including a Makefile) to:




Make a subdirectory called movie for your animation or still.


Include a README file that documents the functionality of your ray tracer. Also, list all the scene files that show off your features and document any extensions you made to the simple scene description language.


Starter Code


Starter code has been provided in C++. For your convenience, they are tar-red here. The following files are included:




The course calendar allows for three weeks to complete the ray tracer. This should be enough time, but some students in the past have found themselves reaching the deadline sooner than they expect. To help you budget your time, we’ve constructed a suggested list of milestones: