Homework 4, due Tuesday, Oct 12

This will be the first of two ray tracing assignments.

As we discussed in class, you can form a ray from a camera into a scene for every pixel of the image. The ray goes from v = [vx,vy,vz] into direction w = [wx,wy,wz].

We can just place the camera eyepoint at the origin, so the first v will be [0,0,0]. Of course, when we start bouncing rays off of objects to get reflections, shadows, etc., then v will take on all sorts of values.

You can calculate w for any pixel (i,j) by placing the image into the scene as sort of film plane, as we discussed in class. You can put it along the z axis, at z = -focalLength. Remember, the smaller the value you choose for focalLength, the more wide angle will be the view. You will get reasonable looking pictures at focalLength values of around 3.

If your image has W columns by H rows, then you can make an applet that extends class PixApplet.java. Your class should compute a color at every pixel by tracing a ray into the scene:

   double rgb[] = {0,0,0};
   double v[] = {0,0,0};
   double w[] = {0,0,0};

   ....

   public void setPix(int frame) { // SET PIXELS FOR THIS ANIMATION FRAME
                                   // (THIS OVERRIDES A METHOD IN PIXAPPLET CLASS)
      v[0] = 0;
      v[1] = 0; // CAMERA EYEPOINT IS AT THE ORIGIN
      v[2] = 0;

      int n = 0;
      for (int j = 0 ; j < H ; j++)   // LOOP OVER IMAGE ROWS
      for (int i = 0 ; i < W ; i++) { // LOOP OVER IMAGE COLUMNS

         w[0] = (double)(i - W/2) / W;     // COMPUTE RAY DIRECTION AT EACH PIXEL
         w[1] = (double)(H/2 - j) / W;     //
         w[2] = -focalLength;              // PLACE IMAGE PLANE AT z = -focalLength

         rayTrace(v, w, rgb);              // RAY TRACE AT THIS PIXEL

	 pix[n++] = pack(Math.max(0,Math.min(255,(int)(255 * rgb[0]))),
	                 Math.max(0,Math.min(255,(int)(255 * rgb[1]))),
	                 Math.max(0,Math.min(255,(int)(255 * rgb[2]))));
      }

Given a ray v,w, and a collection of spheres, each of which is described by center coordinates and radius [cx,cy,cz,r], we can figure out which sphere the ray hits (if any) as follows:

  1. Set t = infinity
  2. Set object = null
  3. Loop through all the spheres. For each spheren (with center cx,cy,cz and radius r):
    1. Try to intersect the ray with spheren, to get tn;
    2. If the ray intersects spheren at tn, and tn < t, then this is the nearest sphere, so:
      1. Set t = tn
      2. Set object = spheren
  4. if object == null then
            return background color

  5. Compute surface point S = v + tw
  6. Compute surface normal n = (S-[cx,cy,cz])/r
  7. Compute reflection vector R = -2(wn)n + w
  8. Create reflected ray with v = (SR) and w = R.
  9. Recursively call this algorithm to compute the colorR seen by the reflected ray.
  10. Return the product of colorR and the color of object.

If you want to play it safe, you can start out by making a version of this applet that sets each of your spheres to a single solid color, just so you can check your basic ray tracing logic, and then add the reflection stuff after you get that first part working.

As we discussed in class, you can intersect ray v,w with sphere

(x-cx)2 + (y-cy)2 + (z-cz)2 = r2
by substituting (vx + t wx) for x, (vy + t wy) for y, and (vz + t wz) for z in the sphere equation.

When you do this you'll get some quadratic equation in t. There are two possibilities: Either (i) this equation will have no real roots (which means the ray missed the sphere entirely), or else (ii) the equation will have two roots, which means the ray has indeed hit the sphere. In this case, the value of t that you want is the smaller of these two roots, because that's where ray hits the front of the sphere.

So let's do this substitution:

( vx + t wx - cx ) 2 + ( vy + t wy - cy ) 2 + ( vz + t wz - cz ) 2 = r2
Multiplying this out, we get:

(vx-cx) 2 + 2 (vx-cx)wx + t2 wx 2 + (vy-cy) 2 + 2 (vy-cy)wy + t2 wy 2 + (vz-cz) 2 + 2 (vz-cz)wz + t2 wz 2 = r2

This can be written as the quadratic equation At2 + Bt + C = 0, by rearranging terms:

A = wx 2 + wy 2 + wz 2 ,

B = 2 (vx-cx)wx + 2 (vy-cy)wy + 2 (vz-cz)wz ,
C = (vx-cx) 2 + (vy-cy) 2 + (vz-cz) 2 - r2

A more compact way of saying this using dot products is:

A = ww       B = 2 (v-c) • w       C = (v-c) • (v-c) - r2.

Your job is to come up with an interesting collection of tinted reflecting spheres, and use the above code and equations to ray trace to them, to produce a picture.

If you're feeling ambitious you can try figuring out the equations for other shapes such as cylinders. You might also want to see if you can create a boolean combination (like intersection) of two or more spheres or other shapes.

You might find it useful to rotate the scene view direction in response to mouse drags. You can do this by transforming your original ray v,w by a matrix, just as you did to change view direction in the previous assignment.

Next week we'll work on the more advanced topics like booleans and shading models (which we briefly discussed in this week's class), shadows, other shape primitives and ray perturbation.