Motivation (updated 12/08/19)

In this assignment, you will add two features into your raytracer and begin developing more sophisticated scenes:

  • refraction through spheres and polygons;
  • polygonal smoothing using shared vertices of faces in a model.
smoothGlassCow.png These features are illustrated in the above image of a smooth glass cow. We won't ask you to render this specific image, since cow.obj has roughly 10,000 triangles, but your program should be able to given enough time. It took Ben's C++ implementation about 30 minutes on eight cores for the 1024x1024 image above. In addition to those features, you will begin constructing more sophisticated scenes.

Data Formats

The driver files used for this assignment are the same as in previous assignments with the following modifications:

  • Spheres have one additional field - their refractive index - that is an additional number at the end of a sphere line. Spheres are now sphere x y z r Ka_r Ka_g Ka_b Kd_r Kd_g Kd_b Ks_r Ks_g Ks_b Kr_r Kr_g Kr_b Ni where Ni is the refractive index. A refractive index of 0 corresponds to no refraction, and in that case rays should not be passed through the sphere. In any other case, the transparency of the object (what proportion of the light passes through the object) should be 1-Kr.
  • mtllib files have two fields that will now be used: Tr (a vector corresponding to red, green, and blue), which is the amount of light passing through the object, and Ni (a scalar), which is the refractive index. Additionally, we will use one more value of illum - an illum value of 6 corresponds to a glass-like object (but with reflection still given by a Kr equivalent to Ks). You are welcome to implement more values of illum corresponding to the various combinations of reflection and refraction, but it is not required.
  • Model lines in a driver file will have an additional field coming directly before the name of the model - corresponding to the angle cutoff for smoothing. If this value is 45, the normal for a face's vertex will be calculated as the average of the adjoining faces with angle between their "true" normals and this face's "true" normal less than 45. A value of 0 corresponds to no smoothing.

A few notes on the implementation of smoothing:

  • You will need to know the beta and gamma values when you calculate the smoothed normal for a point. As such, it may be helpful to have your collision methods return the calculated normal vector.
  • Ensure that all calculated normal vectors are normalized.
  • Rather than calculating normals, you can use the vertex normals provided in a model file (noting that you will have to transform them if you transform the model). This is not required for this assignment, but may be useful to implement if you choose to use models with trusted vertex normals later on.

A few notes on the implementation of refraction:

  • If the transparency and reflectivity of an object sum to more than one, the object may appear brighter than intended.
  • Whenever you shoot a ray that collides with a refractive object, you will refract through it and if it is reflective also reflect off it. These values are combined into the color according to the object's transparency and reflectivity. You do not have to implement behavior for calculating reflection and refraction based on the angle of the incoming ray using something like Schlick's approximation to the Fresnel equations (again, you are welcome to if you would like).
  • You may have to keep track of if a ray is inside of an object to correctly calculate the angle of the resulting ray when it leaves that object. It is possible for a ray to be inside multiple refractive objects (with different refractive indices), but you are not required to implement that for this assignment.
  • You will also likely need to have a way to check when you exit an object. For polygons this should be relatively easy, but for spheres it will require adding a check to see if you hit the back of the sphere (i.e. the positive solution to the quadratic solution you are solving).
  • The refractive index outside of any objects is 1.0.
  • When a ray refracts through an object, the recursion level should decrease.
  • There are multiple ways to implement refraction through objects. One method will be presented in class, but you are welcome to implement it in whatever way you wish, as long as it results in similar results
  • For this assignment, do not worry about having objects that intersect. This means that if you have a large refractive sphere, you do not have to worry about the fact that it could have another object inside of it that rays could interact with.
  • Getting an intuitive sense of what refractive objects should look like is hard, especially with polygons. It's recommended that you focus your testing on objects (such as spheres) where you know the expected result.
  • In the standard .mtl file format, Tr is a singular value. There will be three values in the .mtl files we use for the course, but you are welcome to implement a case for dealing with the standard.

A few notes on speeding up your program:

  • Common slowdowns come from doing work multiple times unecessarily - for example, if you compute the average vertex normal across all faces at a vertex every time you calculate the smoothed normal, your program will run slowly. Instead, calculate the vertex normals for each vertex once at the beginning of your program, then interpolate between them using beta and gamma. One way to determine what is causing timing issues in your program is to use a profiler.
  • Allocating extra memory can result in slowdowns. Ideally, your program would allocate memory at the start, then each pixel would allocate memory only for new rays. Implementing this can be difficult if aren't experienced with memory allocation strategies.

Task

This assignment intentionally builds on the previous assignment. It is recommended that as you complete this assignment, you simplify and improve your code where possible to make these and upcoming changes easier.

In this assignment you will construct five scenes: three scenes described in the three driver files given to you and two more scenes of your choice by creating your own driver file with any objects and lights of your choice. Your code will be tested with one additional driver file, for a total of six files. If your code takes longer than 15 minutes to run on any of these driver files, submit with them a .ppm file of the result of the driver and include in your readme the maximum resolution that lets that driver render in under 15 minutes. All driver files should be able to be rendered in under 15 minutes.

One additional thing to note is that the behavior of your raytracer does not have to exactly match the behavior of the given images. As long as it is clear that your raytracer has physically realistic output, matching what is expected for a driver file, you will recieve credit. There are many similar ways to implement refraction (with slightly different outputs), all of which are valid solutions for this assignment

    drivers_and_models_and_ppms.tar This .tar file also includes the driver used to generate the smooth glass cow image and the Python scripts used for generating driver00 and driver01.
  • Scene 0 - the scene described in driver00.txt. It does not use any of the features of this assignment, but demonstrates complex reflection. Expected output is below.
    driver00.png
  • Scene 1 - the scene described in driver01.txt. It demonstrates the effect of smoothing. Expected output is below.
    driver01.png
  • Scene 2 - the scene described in driver02.txt. It demonstrates the effect of refraction and is inspired by variants of the classic Cornell Box. Expected output is below.
    driver02.png
  • Scene 3 - You are providing scene 3 (name it driver03.txt). This scene should simply and obviously illustrate the features added in this assignment.
  • Scene 4 - You are providing scene 4 (name it driver04.txt). This scene should be an appealing illustration of the behavior of your ray tracer.
  • Scene 5 - The GTAs will be providing scene 5 which will be used for grading. It may include any features from this or the previous assignment, and will include at least one refractive polygonal object.

In all cases the camera view, lighting, and object placement should result in a well rendered final image. The image should be written in PPM format as described in P2.

Submission

Submit a tar file via the CANVAS assignment page that includes:

  • Your source files
  • Your driver files
  • Your model and material files
  • Libraries if you use any
  • A makefile if appropriate
  • README.txt file that explicitly contains (1) A command to compile your program and (2) A command to execute it and (3) a description of the maximum resolution that any driver files should be rendered at if they take longer than 10 minutes to render.
  • .ppm output for any drivers that take longer than 10 minutes to render.

If you are using C++, your executable should be named 'raytracer'. If your are using java, the main executable class should be named 'Raytracer'. Notice the change in case for the first letter between C++ and Java. It is necessary for this assignment to take exactly two arguments as described above.

Reminder

There is no “late period”. Key is to start earlier and finish earlier. The program is due when it is due. All work you submit must be your own. You may not copy code from colleagues or the web or anywhere else. Cheating will not be tolerated, and will be handled in accordance with university and department policy.

Update 11/15/19

Clarified Tr format and uploaded modified checkerboard files for driver01.

Update 12/08/19

Drivers, models, and ppm values are accessible at solutions.tar