Chair of Computer Graphics and Visualization

Sheet 1: Recursive Ray Tracing

Exercise: Recursive Ray Tracing (20 points)

So far, you have only traced primary rays from the camera to the objects. Now you will extend the system to support secondary, tertiary, and arbitrarily deep rays for reflection and refraction.

The provided start code already traces primary camera rays, computes intersections, and evaluates the local Phong illumination model at the hit point. Your task in this exercise is to extend that code so that a hit point may spawn additional rays: reflected rays and, when supported by the material, refracted rays. The returned color is then no longer just the local Phong color, but a combination of the local contribution and the recursively traced secondary contributions.

It is important to note that the implementation in this exercise deliberately uses several approximations. These approximations keep the code short, make the control flow easier to understand, and avoid some of the complexity of a physically accurate renderer. The downside is that some design decisions in the implementation are not fully physically correct. In other words, this exercise is not about building a perfect physical light transport simulation, but about adding recursive ray tracing in a simple and manageable way.

Recursion Depth 2 Recursion Depth 3 Recursion Depth 4 Recursion Depth 5 Recursion Depth 6 Recursion Depth 7 Recursion Depth 8 Recursion Depth 9

Raytraced images of the test scene with recursion depths from 2 to 9.

Implement recursive reflection and refraction for all materials that support it. Recursion must be terminated at a predefined depth so that tracing always stops after a finite number of secondary bounces. At the current hit point X, the final color value CX is computed by combining local illumination CX,local, reflected CX,reflected, and transmitted CX,transmitted light. The factors l, r, and t denote the ratios of local illumination, reflected light, and transmitted light, respectively:

                Cₓ = l · Cₓ,local + r · Cₓ,reflected + t · Cₓ,transmitted
            

As a first approximation, we make an artificial distinction between three classes of objects in the scene. This simplifies the implementation and makes the system more efficient, but it is not fully physically correct. In reality, reflection and refraction always come as a pair, so this separation is a modeling shortcut rather than a physical truth. For this exercise, however, it is a useful way to keep the recursion logic simple and manageable. This also means that, when you make implementation decisions, you should follow the simplified model used in the code rather than trying to force a fully physical interpretation onto every case.

We therefore distinguish between the following three material types:

To encode this simplified behavior in the objects, each material has an artificial parameter local. It specifies how much of the final appearance comes from local illumination, i.e. from the Phong illumination model that is already present in the starter code. The remaining part, 1 - local, is then used for recursive effects. Depending on the chosen material class, this remainder is assigned either entirely to reflection, or split between reflection and refraction. So, conceptually, local tells you how much of the surface appearance should stay local, while 1 - local tells you how much should come from secondary rays.

For materials with local illumination only, there are no secondary rays at all. Therefore l = 1, r = 0, and t = 0.

For reflective and refractive materials, the non-local part is shared between reflection and refraction, so 1 - l = r + t. The ratio of r and t is computed using Fresnel equations, with Schlick’s approximation. Here, R₀ denotes the reflectance at normal incidence, θ is the angle between the incoming ray direction and the surface normal, and n is the relative refractive index. Under the simplifying assumption that one side of the interface is always air, compute n from the material IOR, taking care to use the correct ratio depending on whether the ray is entering or exiting the object:

                R(θ) = R₀ + (1 - R₀)·(1 - cos(θ))⁵
                R₀ = ((n - 1)/(n + 1))²
                T(θ) = 1 - R(θ)
                
                r = (1 - l) · R(θ)
                t = (1 - l) · T(θ)
            

For example, for reflective but non-refractive materials (e.g., the yellow sphere), use R₀ = 1 - local, r = R(θ), l = 1 - r, and t = 0. This is another deliberate simplification: physically, a reflective surface model would usually be derived differently, but for this exercise it is enough to treat the non-local part as purely reflective whenever no refraction is supported.

You may assume that:

Use the Vec3 class to compute refracted rays. Note that θ is the angle between the incoming direction vector i and the surface normal n, so cos(θ) is given by their dot product: cos(θ) = i · n.

Implementation hint: the starter code already computes the local Phong illumination term in Scene::traceRay. You should keep that part and extend it by adding recursive reflection, recursive refraction, and the final combination of local and recursive contributions.

In particular, the missing work is roughly as follows:

A useful practical hint is that, under the assumptions of this exercise, you can determine whether a ray is entering or leaving an object from the sign of the dot product between ray direction and surface normal. Also, when you spawn a secondary ray, offset its origin by a small epsilon so that it does not immediately intersect the same surface again due to numerical precision errors.

Loading

Drag with the left mouse button or tab and drag to rotate the scene. Stop interacting to start the raytracing.