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:
Sph = (x-cx)2 + (y-cy)2 + (z-cz)2 = r2by 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 = r2Multiplying 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 = w w 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:
f(S) = (x - cx)2 + (y - cy)2 + (z - cz)2 - r2Taking 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.