Ray tracing 1: Assignment due Tuesday Nov 13 before class

For next Tuesday, in addition to finishing adding Phong to your Zbuffer (if you haven't already done so), you will be implementing the beginnings of ray tracing.

As we discussed in class, to ray trace into a scene, you form a ray from the camera point into the scene for every pixel of the image. Recall that in general, a ray goes from v = [vx,vy,vz] into direction w = [wx,wy,wz], where w is a unit length direction 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 ]

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 a sort of film plane, 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 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 create the ray at each pixel by:

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

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

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

      w[0] = (double)(i - W/2) / (W/2); // COMPUTE RAY DIRECTION AT EACH PIXEL
      w[1] = (double)(H/2 - j) / (W/2); //
      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. Set t = infinity
  2. Loop through all the spheres. For each sphere Sn
    1. Try to intersect the ray with Sn, to get tn;
    2. If the ray intersects Sn at tn, and tn < t, then this is the nearest sphere, so:
      1. Set t = tn
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.

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.

Your job 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.

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