Ray tracing 1: Assignment due Wednesday April 22 before class

For next Wednesday you will be starting to implement ray tracing.

As we discussed in class, to ray trace into a scene, you shoot a ray, for each pixel in turn, from the camera point into the scene.

In general, a "ray" (v,w) is essentially half of a line, given by the parametric equation v + tw. The ray starts at point v = [vx,vy,vz] and travels toward direction w = [wx,wy,wz], where w is a unit length vector. As parameter t varies from zero to infinity, a point long the ray travels to points [ vx + t wx, vy + t wy, vz + t wz ]

If we place the camera eyepoint at the origin, v will be [0,0,0]. Of course, when we start bouncing rays off of objects to get reflections, shadows, and so on, 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 a sort of film plane floating in front of the camera, as we discussed in class. Let's put this plane along the z axis, at z = -focalLength. Just as with your ZBuffer rendering, the smaller the value you choose for focalLength, the wider will be the view angle. You get reasonable looking pictures at focalLength values of around 3.

If your image has W columns by H rows, then you can create the ray at each pixel by:


   rgb[] = new double[3];
   v  [] = new double[3];
   w  [] = new double[3];

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

      v[0] = 0;
      v[1] = 0;                     // CAMERA EYEPOINT IS AT THE ORIGIN
      v[2] = 0;

      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
      normalize(w);

      rayTrace(v, w, rgb);          // COMPUTE COLOR AT PIXEL BY RAY TRACING
      setPixel(i, j, rgb);
   }

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 first (if any) as follows:

  1. double t = infinity
  2. Sphere Sph = null
  3. Loop through all the spheres. For each sphere Sphn
    1. Try to intersect the ray with Sphn, to get tn;
    2. If the ray intersects Sphn at some tn, and tn < t, then this is the nearest sphere, so:
      1. t = tn
      2. Sph = Sphn
As we discussed in class, you can intersect ray (v,w) with sphere
Sph = (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.

For now, we will just do phong shading on each sphere, using the sphere's surface normal. As I said in class, there are two distinct ways to think about computing the sphere's surface normal. In both cases, given that you have computed t where the ray hits the sphere, you first obtain the point where the ray hits the sphere by evaluating S = [ vx + t wx, vy + t wy, vz + t wz ]. Then, either:

  1. Take the difference vector from the center of the sphere to this point S - C. Normalize that difference vector, and you have the surface normal.

  2. A more general way to think about computing the surface normal - which has the advantage that it will work for any shape described by an implicit function, not just spheres - is to use the derivative of the implicit function at point S. In the case of our sphere:
    f(S) = (x - cx)2 + (y - cy)2 + (z - cz)2 - r2
    Taking the x,y,z partial derivatives we get:
    f'(S) = [2(x - cx), 2(y - cy), 2(z - cz)].
    Normalize the above vector to get the surface normal at surface point S.

Assignment due Wednesdday April 22 before class

Your job for next week is to come up with an interesting collection of spheres, each of which is Phong shaded, and ray trace to them to produce a picture. Be creative. You can make a snowman or a strange animal or your favorite molecule, or something else entirely.

Next week we'll work on how to ray trace to other shapes, as well as more advanced topics like reflection, refraction and shadows.