Notes for Monday September 14 class -- Intro to ray tracing

Images

An image is essentially just an array of pixels. Conceptually, the pixels are organized into a two dimensional grid of rows and columns. But in reality, the entire image is generally stored as a contiguous one dimensional array of pixels. Each pixel stores a color, which usually contains a red, a green and a blue component.

Color perception

The human eye can see a spectrum of light within the range of about 400 nanometers to 700 nanometers in wavelength. As you can see in the figure, our red receptor cells sensitve to mostly longer wavelengths, and a little bit of very short wavelengths. Our green receptors are sensitive to somewhat shorter wavelengths than our red receptors. Our blue receptors are sensitive to shorter wavelengths.

In practice, we approximate the color at each pixel of an image by a vector of three numbers: [red, green, blue].

Shooting a ray at a pixel

Rendering an image by ray tracing consists of shooting a mathematical ray from an eye point through each pixel of the image into the 3D scene, as shown in the figure. To render the pixel, we need to find out what object, if any, the ray hits first.

For each pixel, we need to form a different ray. A ray consists of an origin point V and a unit length direction vector W. A point P along the ray is defined by P = V + t * W, where t, the distance along the ray, is a non-negative number.

Given a pixel with (x,y) coordinates, and a distance f from the eye to the image plane, V is given by [0,0,f], and W is given by normalize([x,y,-f]).

Ray tracing to a sphere

As shown in the image below, we intersect a ray with a sphere by considering two equations:

  • P = V + t * W (a point along a ray)

  • x*x + y*y + z*z = r*r (a point on a radius r sphere at the origin)
(Continued below the figure)

We can do this much more easily if we use dot products:

dot(A, B) = Ax * Bx + Ay * By + Az * Bz
If vectors are encoded as arrays, then the Javascript code code to implement this is:
function dot(A, B) {
   return A[0] * B[0] + A[1] * B[1] + A[2] * B[2];
}
Given a sphere with center C and radius r, we ray trace to it as follows:

Move the sphere to the origin by shifting coordinates. Essentially, this means subtracting the sphere center from ray origin V:

   V = V - C
Now we combine the definition of a point along a ray:
   [x,y,z] = V + t * W
with the definition of a point on a sphere of radius r at the origin:
   x*x + y*y + z*z = r*r
If we look at the individual x,y,z coordinates of points along the ray:
   [x,y,z] = [Vx + t * Wx, Vy + t * Wy, Vz + t * Wz]
Then we can substitute the terms in the ray equation into the sphere equation:
   (Vx + t * Wx) * (Vx + t * Wx) +
   (Vy + t * Wy) * (Vy + t * Wy) +
   (Vz + t * Wz) * (Vz + t * Wz) = r * r
or:
         ( Wx * Wx + Wy * Wy + Wz * Wz ) * t2
   + 2 * ( Vx * Wx + Vy * Wy + Vz * Wz) * t
   +     ( Vx * Vx + Vy * Vy + Vz * Vz - r * r ) = 0
Now we can compute t by considering the quadratic formula:
   t = ( -B +- sqrt(B2 - 4AC) ) / 2A

     = ( -B/2 +- sqrt((B/2)2 - AC) ) / A
We can use the definition of dot product to find our A,B and C terms to plug into the quadratic formula.
   A   = W•W = 1
   B/2 = V•W
   C   = V•V - r2
And that gives us the answer:
   t = -V•W - sqrt((V•W)2 - V•V + r2)
Now we can move the origin back to where is belongs:
   V = V + C
and use t to compute the point of intersection of the ray with the sphere:
   P = V + t * W
We can also compute the normal vector perpendicular to the sphere surface, which we will need in order to shade the sphere:
   N = normalize(P - C)