Notes for Wednesday February 17 class -- ray tracing and phong shading

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 fl from the eye to the image plane, V is given by [0,0,fl], 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 product, which is a built-in function in GLSL:

dot(A, B) = Ax * Bx + Ay * By + Az * Bz
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 ) * t^2
   + 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(B^2 - 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 - r^2
And that gives us the answer:
   t = -V • W - sqrt((V • W)^2 - V • V)
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)

 

Implementing a ray tracer in a fragment shader

In class we showed how to implement a simple ray tracer, using the math that we developed to ray trace to a sphere.

Our ray tracer renders the sphere, and also applies simple lighting.

 

Scattering light from a surface

Surfaces are rarely completely flat. If you look through a microscope, most surfaces like like tiny mountain ranges, with hills and valleys and pitting, often caused by the normal wear and tear of things rubbing against other objects.
Plastics have two types of reflectance

Some light bounces off the clear acrylic surface. This light is not affected by the plastic color, since it never interacts with the dye particles inside the plastic. For this reason, specular highlights on plastic are white.

Some light enters into the clear plastic acrylic, where it encounters dye particles. The colored light that re-emerges has been highly scattered after bouncing off of many dye particles, and therefore creates a diffuse reflection.

Metals have only one type of reflectance

Both the specular and diffuse components of metal are created by light interacting with the surface. You can think of the surface of metal as consisting of tiny mountain ranges. Some light bounces off the tops of the mountains (where the metal surface has worn down, flattening the mountaintops). These reflections look relatively specular and mirror-like. Other light enters down into the crags of the mountains, where it bounces around multiple times. These reflections look diffuse. Both types of reflections take on the color of the metal. For example, both the specular and diffuse components of gold will be yellow in color.
Three components of the Phong model

 

Implementing Phong reflection

We implemented just a single light source in the fragment shader, and added most of the Phong reflection model for multiple light sources.

I only implemented the ambient and diffuse components of Phong reflection. I left instructions in the code to help you implement the specular component, which you will be doing as part of your homework.

In order to do that, you will first need to construct the reflection vector R, which represents the mirror image about surface normal N of the vector from the surface point to the direction LDir. As we showed in class, given a light source direction LDir, R is computed by:

R = 2 (N • LDir) N - LDir

After you have computed R, you then need to take the dot product of R and the direction to the eye E raised to specularPower, (where the value of specularPower is stored in Specular[i].w), and multiply by both the specularColor (which is stored in Specular[i].rgb), and the light color LCol:

specularColor * max(0, R • E)specularPower * LCol

The direction E to the eye is just the direction tracing back along our ray from V to W, so E is just -W.

The resulting color is multiplied by the specular color and then added to the total surface color to create a highlight from this light source.

 

Homework

Due next Wednesday before the start of class

Create your own scene that consists of ray tracing to spheres.

You can start with the code we implemented in class.

Complete the included code in hw2.zip and follow the notes in the fragment shader code to implement the specular component of Phong reflection.

Have fun with it. Here are some things you might try:

  • See if you can figure out how to ray trace to two or more spheres. Maybe you can create an interesting character.
  • Try to create other sorts of natural materials using the noise-based procedural texture.
  • See if you can figure out how to create multiple light sources.
  • Try anything else that inspires you. Perhaps a sky gradient.
You can also take this opportunity to create a cool new scene with multiple light sources and interesting animations.

A caution: You always need to make sure that the light direction vectors in LDir are normalized to unit length.

As usual, see if you can create something fun and original. Feel free to add other capabilities if you are feeling ambitious. We definitely give extra credit for work that goes above and beyond. :-)