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.
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.
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:
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.
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
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
}
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.
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.
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.
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.
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 for this assignment is exactly the same as previous assignments Ð copy all your code (including a Makefile) to:
/afs/andrew/scs/cs/15-462/students/<andrew_id>/asst3/
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 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: