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:
(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.
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.