Ray Tracing
Ray tracing simulates the physical behavior of light by tracing rays from the camera through each pixel into the scene. It naturally handles reflections, refractions, shadows, and global illumination.
Basic Ray Tracing
For each pixel (x, y):
1. Generate ray from camera through pixel:
origin = camera.position
direction = normalize(pixel_position - camera.position)
2. Find closest intersection with scene:
for each object in scene:
t = intersect(ray, object)
if t < closest_t:
closest_t = t
closest_object = object
3. If hit: compute color using lighting model
If miss: return background color
Ray equation:
P(t) = origin + t * direction
t > 0 (in front of camera)
Ray-Sphere Intersection
Sphere: center C, radius r
Ray: P(t) = O + t*D
Substitute into sphere equation:
|P - C|² = r²
|O + tD - C|² = r²
Let oc = O - C
a = D·D
b = 2*(oc·D)
c = oc·oc - r²
discriminant = b² - 4ac
if discriminant < 0: no intersection
if discriminant = 0: one intersection (tangent)
if discriminant > 0: two intersections
t = (-b ± √discriminant) / (2a)
Take the smaller positive t
Ray-Triangle Intersection
Moller-Trumbore algorithm:
Edges: E1 = V1 - V0, E2 = V2 - V0
h = D × E2
a = E1 · h
if |a| < epsilon: ray parallel to triangle
f = 1/a
s = O - V0
u = f * (s · h)
if u < 0 or u > 1: miss
q = s × E1
v = f * (D · q)
if v < 0 or u+v > 1: miss
t = f * (E2 · q)
if t > epsilon: hit at t
Barycentric: (1-u-v, u, v)
Reflections and Shadows
Reflection:
R = D - 2*(D·N)*N
Trace new ray from hit point in direction R
Color = local_color + reflection_coeff * reflected_color
Shadows:
For each light, trace shadow ray from hit point toward light
If shadow ray hits an object before reaching light:
point is in shadow (no direct lighting)
shadow_ray = (light_pos - hit_point)
if any_object.intersects(shadow_ray):
color -= diffuse + specular
Recursive Ray Tracing
ray_color(ray, depth):
if depth == 0: return background
hit = find_closest_intersection(ray)
if no hit: return background
color = local_illumination(hit)
if hit.object.is_reflective:
reflect_ray = compute_reflection(ray, hit)
color += ks * ray_color(reflect_ray, depth-1)
if hit.object.is_transparent:
refract_ray = compute_refraction(ray, hit)
color += kt * ray_color(refract_ray, depth-1)
return color
Typical max depth: 5-10 bounces