Ray Tracing



Introduction


Ray tracing is a technique that traces a ray from the center of projection (the eye) trough a pixel. Then it follows the ray into the 3D scene until it strikes an object. It then uses the geometry of that object and the position and brightness of the light sources to determine the pixels color.

Using this single algorithm, ray tracing handles:

1. Ambient light
2. Diffuse reflection
3. Specular reflection
4. Hidden surface removal
5. Smooth shading of curved surfaces (spheres, cylinders)
6. Shadows
7. Mutually overlapping objects
8. Objects that pierce other objects
9. Reflective objects


Sphere geometry explanation


The center of projection is at (cx, cy, cz), and the pixel is at (px, py, pz). The vector leading through the pixel coming from the center of projection then has components [px-cx, py-cy, pz-cz].
The points along this ray have coordinates given by (cx, cy, cz)+t*[px-cx, py-cy, pz-cz] for different values of t. For example, the X coordinate of a point on the ray is given by:

cx + t * (px - cx)

where t>=0. Values of t less than zero correspond to points behind the center of projection, so you can't see them.

To find the point where the ray intersects the nearest object, the program can calculate t for the point of intersection with each object. It then takes the intersection with the smallest positive value for t.

You can create a FindT function for each object, wich returns the smallest positive value for t.

For example, the equation for a sphere centered at position (cx, cy, cz) is:

(cx - x)^2 + (cy - y)^2 + (cz - z)^2 - radius^2 = 0

You can write the equation of a line through point p along the vector v using parametric equations (functions like X(t), Y(t), Z(t)) like this:

X(t) = px + t * vx
Y(t) = py + t * vy
Z(t) = pz + t * vz


If you substitute these values into the equation for the sphere, you get:

(cx - px + t * vx)^2 + (cy - py + t * vy)^t + (cz - pz + t * vz)^2 - radius^2 = 0

After rearranging this, you get:

A * t^2 + B * t + C = 0

Where:

A = vx^2 + vy^2 + vz^2
B = 2 * vx * (px - cx) +
2 * vy * (py - cy) +
2 * vz * (pz - cz)
C = cx^2 + cy^2 + cz^2 +
px^2 + py^2 + pz^2 -
2 * (cx * px + cy * py + cz * pz) - radius^2


The solutions to this equation are given by the quadratic formula as:

t = -B +/- Sqr(B^2 - 4 * A * C) / 2 / A

If B^2 - 4 * A * C < 0, the square root has no solutions. Then the ray does not intersect the sphere.

If B^2 - 4 * A * C = 0, the equation has one solution, -B/2/A.

If B^2 - 4 * A * C > 0, the equation has two solutions. Use the smallest value. For further explanation, see the code.

Finding hit color


If you have detected the smallest t value you can calculate the hit color. For this, you need to know something called the surface normal. This is a vector perpendicular to the surface. By a sphere, this vector is given by:

[px - cx, py - cy, pz - cz]

where p is the point on the sphere and c is the center of the sphere.
Before you can calculate the hit color, you must normalize this vector. This is a process making sure that the length of the vector = 1. First, calculate the current length. This is simple. The length is given by Sqr(vx^2 + vy^2 + vz^2). Second, divide the components of the vector by the length of it. Then you can call the CalculateHitColor subroutine to calculate the hit color.

Lighting model


The lighting function for ray tracing is:

I = Ia * Ka + Ii * (Kd * (L . N) + Ks * (R . V)^n)

Where:

I = the total intensity
Ia = the intensity of the ambient light
Ka = the reflecting value of ambient light
Ii = the intensity of the light source
Kd = the diffuse reflection value
L = a vector from the surface to the light source
N = the normal vector
Ks = the specular reflection value
R = a vector from the surface at the mirror direction of the vector L (the reflection vector)
V = a vector from the surface to the viewpoint
n = the specular constant

After this the reflected factor is added. You can find the reflected light by tracing a ray along a vector VM wich is defined by:

VMx = 2 * Nx * V . N - Vx
VMy = 2 * Ny * V . N - Vy
VMz = 2 * Nz * V . N - Vz


Where V . N is the dot product between the vector from the point on the surface and the surface normal, N is the surface normal vector, and V is the vector from the point on the surface to the viewpoint. Now you trace the ray, and you add the returned RGB values multiplied by the objects reflected light parameters.