Home

Assignment 6 - Ray Tracer

Due Tuesday 4/27 at 11:59 pm. You must work individually.

Goal

In this assignment, you will be writing a ray tracer with the following features:

Associated Labs

Starting point

The skeleton code for Assignment 1 is a good starting point. Just like A1, this assignment does not use OpenGL and instead writes the result as an image file. You may also reuse any of your previous code from this course for this assignment.

The command line argument should be:

> ./A6 <SCENE> <IMAGE SIZE> <IMAGE FILENAME>

Camera

Set up the camera manually with the following parameters:

     

Imagine a virtual plane at Z=4.0 (i.e., one unit away from the camera, which is at Z=5.0). Our virtual rays will be starting at (0, 0, 5) and then will be going through the center of each pixel in the virtual plane. For example, in the left image, there are 9 rays, including one going straight out through the center of the middle pixel. The right image shows how these rays would look for a 10 by 10 image. (This was rendered with OpenGL for pedagogical purposes. Your code does not need to show the virtual scene in 3D.)

To start, write a function that can generate these rays given the camera specifications above, and the width/height of the output image from the commandline argument. With a 3x3 image, the 9 rays should have the following directions (each column is a unit direction vector):

    0.2572      0.0000     -0.2572      0.2662      0.0000     -0.2662      0.2572      0.0000     -0.2572
    0.2572      0.2662      0.2572      0.0000      0.0000      0.0000     -0.2572     -0.2662     -0.2572
   -0.9315     -0.9639     -0.9315     -0.9639     -1.0000     -0.9639     -0.9315     -0.9639     -0.9315

(Click here for a screenshot of the data in case your screen is too small.) Since the camera is not rotated, the middle ray’s direction is (0, 0, -1), straight ahead along the negative Z direction.

Scenes 1 & 2

Your first scenes consist of three spheres and one light. Scene 1 is without shadows, and Scene 2 is with shadows. If you complete Scene 2, you do not need to keep the code for Scene 1. In other words, when the <SCENE> argument is set to 1, either of the images below will give you full points. When the <SCENE> argument is set to 2, only the right image below will give you full points.

     
(Left) Without shadows. (Right) With shadows.

To create the scene, you can hard code the values in your code. (You may also use a parser if you prefer.) These values must be used when the command line argument <SCENE> is set to 1 or 2. Make sure to use exactly these values, since they will be used to test your code with an automatic script.

Light

Red Sphere

Green Sphere

Blue Sphere

I highly recommend writing test cases for the collision functions. For example, place a unit-radius sphere at the origin and shoot a ray from (0, 0, 5) with direction (0, 0, -1). The ray should hit the sphere at (0, 0, 1) and (0, 0, -1). Try other test cases, with a different radius and/or position, as well as different rays.

Once your intersection functions have been tested, you’re ready to start implementing a ray tracer. First, shoot just the primary view rays and not the shadow rays (Scene 1, left image above). Once you get the correct result, add the shadow rays (Scene 2, right image above).

Your code should be efficient enough to generate a 1024 by 1024 image without having to wait a long time. It should only take a few seconds at most, even on an older computer. If your code is slow, make sure you are not passing big STL vectors by value and that you are running your code in release mode. Excessively slow code will be penalized.

Also, use object-oriented design to organize your code. There should be a superclass that represents all shapes. The subclasses should implement specific intersection tests. For example, a subclass that represents an infinite plane should implement Task 2 from Lab 13, and another subclass that represents a sphere should implement Task 3 from Lab 13.

Scene 3

The next scene consists of one sphere, one ellipsoid, one infinite plane, and two lights.

     
(Left) Ray traced scene. (Right) A rotated view showing one of the view rays. The blue shadow ray reaches the light, but the green shadow ray is blocked.

Light 1

Light 2

Red Ellipsoid

Green Sphere

Plane

With two lights, you should be able to see areas that are occluded from both or just one light. Also note that the ellipsoid casts a shadow on the sphere.

Scenes 4 & 5

Your next scenes consist of two lights, two Phong spheres, two reflective spheres, and two infinite planes. Scene 4 is with a single reflection, and Scene 5 is with multiple (recursive) reflections. If you complete Scene 5, you do not need to keep the code for Scene 4. In other words, when the <SCENE> argument is set to 4, either of the images below will give you full points. When the <SCENE> argument is set to 5, only the right image below will give you full points.

           
(Left) Rendered with a single bounce. Without enough recursion depth, the reflection of the other reflective sphere is not rendered. (Center) A closeup of multiple reflections. (Right) Rendered with multiple bounces.

Light 1

Light 2

Red Sphere

Blue Sphere

Floor

Back Wall

Reflective Sphere 1

Reflective Sphere 2

Scenes 6 & 7

For these scenes, import an obj mesh. Scene 6 is without model transformation, and Scene 7 is with model transformation. Once you finish Scene 7, you should set up your code so that Scene 6 uses the identity transform.

For triangle-ray tests, use the optimized code by Thomas Akenine-Moller. Some hints for this piece of code:

Without any optimizations, using the bunny mesh will take a very long time to render, since each ray will need to be tested against every single triangle. Add a simple optimization by putting a bounding sphere around the bunny and testing the ray against the sphere first. If the ray does not hit the sphere, you do not need to test against any of the triangles. It should not take more than a minute to render a bunny with a single light at 512x512 resolution. Make sure to run your code in release mode. We will be testing your submission with the bunny mesh.

There should be a single light in the scene:

Now add the ability to transform the obj mesh. To do this, you need to transform the ray into local coordinates, perform collision detection, and then transform the result back to world coordinates. Let \(E\) be the 4x4 transformation matrix of the obj mesh. Then:

  1. Transform ray to local coordinates.
  2. Perform collision detection in local coordinates, using the transformed ray.
  3. Transform results to world coordinates.

For Task 7, there should be a single light in the scene:

We will be testing your submission with the bunny mesh with the following model transform:

E =

    1.5000         0         0    0.3000
         0    1.4095   -0.5130   -1.5000
         0    0.5130    1.4095         0
         0         0         0    1.0000

This transformation matrix can also be constructed as the product E = T * R * S, where

Scene 8

Implement a camera that can be translated/rotated arbitrarily in the world and whose field of view can be modified. Use the same setup as Scene 1 but from a different camera location/orientation. The camera should be placed at (-3,0,0) looking along the positive X axis, with the field of view of 60 degrees. The left image is the 3D view from the original view point of Scene 1, and the right image is the resulting ray traced image.

Bonus

Once you finish the base assignment, you can earn up to 20 bonus points by implementing the following features (in no particular order):

Please use Scene 0 or 9 for the bonus scenes. The other scene numbers must work as if no bonus were implemented.


(Left) Refraction. (Center) Blend between reflection and Blinn-Phong [Nkemdi Anyiam 2021]. (Right) Spherical environment mapping [Rebecca McFadden 2021].


(Left) Area lights [Michael Stewart 2021]. (Right) Monte-Carlo path tracing [Jonah Taylor 2021].

Grading

In each task, you must use object-oriented design to obtain full points.

Total: 100 plus 20 bonus points.

For honors students: you must complete at least 10 bonus points. Your final assignment grade will be computed as:

if bonus >= 10
   grade = base + bonus;
else
   grade = base + bonus - 10;

What to hand in

Failing to follow these points may decrease your final score. On Linux/Mac, make sure that your code compiles and runs by typing:

> mkdir build
> cd build
> cmake ..
> make
> ./A6 <SCENE> <IMAGE SIZE> <IMAGE FILENAME>

If you’re on Windows, make sure that you can build your code using the same procedure as in Lab -1.


Generated on Mon May 3 09:10:15 CDT 2021