Introduction: Beyond Reflection - Adding Transparency

Over the past four lessons, you've built a capable ray tracer that can render realistic scenes with smooth antialiasing, natural lighting through path tracing, and two fundamental material types. Your Lambertian diffuse materials scatter light randomly to create matte surfaces like chalk or unfinished wood, while your metal materials reflect light in a mirror-like way to simulate shiny surfaces like polished chrome or brushed aluminum. These two material types already give you considerable expressive power, allowing you to create scenes with rich visual variety and realistic material interactions.

However, if you look around the real world, you'll notice an important class of materials that your ray tracer cannot yet render: transparent materials. Think about a glass window, a crystal vase, a water-filled drinking glass, a diamond ring, or even ice cubes in a beverage. These materials have a distinctive appearance that sets them apart from both matte and metallic surfaces. They don't simply scatter light like diffuse materials, nor do they just reflect it like metals. Instead, transparent materials do something more complex: they both reflect light from their surfaces and transmit light through their volume, bending the transmitted light as it passes through.

This dual behavior creates the characteristic appearance of glass and other transparent materials. When you look at a windowpane, you can see through it to objects on the other side, but you can also see faint reflections of objects on your side. The balance between transmission and reflection changes depending on the viewing angle. When you look straight through a window, you see mostly the transmitted light with only faint reflections. When you look at a window from a steep angle, the reflections become much stronger and the window starts to look almost mirror-like. This angle-dependent behavior is called the Fresnel effect, and it's one of the key characteristics that makes transparent materials look realistic.

The bending of light as it passes through transparent materials is called refraction, and it's responsible for many familiar optical effects. Refraction is why a straw appears to bend when you put it in a glass of water, why objects look distorted when viewed through a curved glass surface, and why diamonds sparkle with such brilliance. Different materials bend light by different amounts, characterized by a property called the refractive index. Air has a refractive index close to one, water is about 1.33, typical glass is around 1.5, and diamond is approximately 2.4. The higher the refractive index, the more the material bends light, and the more dramatic the optical effects become.

Understanding Refraction and Snell's Law

When light travels through a uniform medium like air or glass, it moves in straight lines at a constant speed. However, when light crosses the boundary between two different materials, something interesting happens: the light changes direction. This bending of light at material boundaries is called refraction, and it occurs because light travels at different speeds in different materials. Light moves fastest in a vacuum, slightly slower in air, noticeably slower in water, and even slower in glass or diamond. When a light ray enters a material where it travels more slowly, the ray bends toward the perpendicular to the surface. When it enters a material where it travels faster, the ray bends away from the perpendicular.

The relationship between the angles and the materials is described by Snell's Law, one of the fundamental principles of optics. Snell's Law states that when light crosses a boundary between two materials, the product of the refractive index and the sine of the angle remains constant. Mathematically, we write this as n₁ sin(θ₁) = n₂ sin(θ₂), where n₁ and n₂ are the refractive indices of the first and second materials, and θ₁ and θ₂ are the angles the light ray makes with the surface normal in each material. The refractive index is a dimensionless number that characterizes how much a material slows down light compared to a vacuum. Air has a refractive index very close to one, meaning light travels through air at nearly the same speed as in a vacuum.

To understand Snell's Law intuitively, imagine a car driving from a paved road onto a sandy beach at an angle. The wheels that hit the sand first will slow down while the wheels still on the pavement continue at full speed, causing the car to turn toward the perpendicular to the beach edge. Light behaves similarly when entering a slower medium. Conversely, if the car drives from sand back onto pavement, it will turn away from the perpendicular as the wheels regain speed. This mechanical analogy helps explain why light bends toward the normal when entering a denser medium and away from the normal when entering a less dense medium.

When Refraction Fails: Total Internal Reflection

Snell's Law works beautifully when light travels from a less dense medium into a denser one, such as from air into glass. The light bends toward the normal, and there's always a valid refracted ray direction. However, something interesting happens when light travels in the opposite direction, from a denser medium into a less dense one, such as from glass into air or from water into air. In these cases, the light bends away from the normal, and at certain angles, something remarkable occurs: refraction becomes impossible, and all the light reflects back into the denser medium instead. This phenomenon is called total internal reflection, and it's responsible for many striking optical effects.

To understand why total internal reflection occurs, let's revisit Snell's Law: n₁ sin(θ₁) = n₂ sin(θ₂). When light travels from a denser medium (higher refractive index) to a less dense medium (lower refractive index), we have n₁ > n₂. Rearranging Snell's Law to solve for the refracted angle gives us sin(θ₂) = (n₁/n₂) sin(θ₁). Since n₁ > n₂, the ratio n₁/n₂ is greater than one. This means sin(θ₂) is larger than sin(θ₁), so the refracted ray bends away from the normal, making a larger angle with the normal than the incident ray did.

The problem arises when the incident angle becomes large enough that the formula would require sin(θ₂) to exceed one. Since the sine of any real angle cannot exceed one, this represents a mathematical impossibility. There is no real angle θ₂ that satisfies Snell's Law in this situation. Physically, this means the light cannot refract into the second medium at all. Instead, all the light reflects back into the first medium, as if the boundary were a perfect mirror. This is total internal reflection, and it occurs whenever the incident angle exceeds a critical angle determined by the refractive indices of the two materials.

The Fresnel Effect and Schlick's Approximation

Even when total internal reflection doesn't occur, transparent materials don't simply refract all the light that hits them. In reality, some light reflects off the surface while the rest refracts through it. The proportion of light that reflects versus refracts depends on the angle at which the light hits the surface, a phenomenon known as the Fresnel effect, named after the French physicist Augustin-Jean Fresnel, who first described it mathematically in the early 1800s. You've probably observed the Fresnel effect many times without realizing it. When you look straight through a window, you see mostly what's on the other side with only faint reflections of your room. But when you look at the same window from a steep angle, the reflections become much stronger and the window starts to look almost like a mirror.

The Fresnel effect is a fundamental property of all interfaces between materials with different refractive indices, not just transparent materials. Even metals exhibit Fresnel effects, though they're less noticeable because metals already reflect most light. For dielectric materials like glass, water, or plastic, the Fresnel effect is quite pronounced. At normal incidence (when light hits the surface straight on), only a small percentage of light reflects. For typical glass with a refractive index of 1.5, about four percent of the light reflects at normal incidence and ninety-six percent transmits through. As the angle increases and the light hits the surface more obliquely, the reflection percentage increases dramatically. At grazing angles (nearly parallel to the surface), almost one hundred percent of the light reflects, regardless of the material's refractive index.

The exact Fresnel equations that describe this behavior are somewhat complex, involving different formulas for light polarized parallel and perpendicular to the plane of incidence. For real-time rendering and ray tracing, we typically use an approximation developed by Christophe Schlick in 1994. Schlick's approximation provides a simple formula that closely matches the full Fresnel equations while being much faster to compute. The approximation is based on the observation that the reflectance varies smoothly from a base value at normal incidence to nearly one hundred percent at grazing angles, and this variation can be approximated by a polynomial function.

Schlick's approximation formula is R(θ) = R₀ + (1 - R₀)(1 - cos(θ))⁵, where R(θ) is the reflectance (the fraction of light that reflects) at angle θ, and is the reflectance at normal incidence. The base reflectance depends on the refractive indices of the two materials and is calculated as . For an air-glass interface with and , we get , confirming that about four percent of light reflects at normal incidence.

Building the Dielectric Material Class

Now that we have the mathematical tools for refraction, total internal reflection, and the Fresnel effect, we're ready to implement the dielectric material class. This class will bring together all the concepts we've discussed to create realistic transparent materials. The dielectric material needs to handle several cases: determining whether a ray is entering or exiting the material, checking for total internal reflection, applying Schlick's approximation to choose between reflection and refraction, and calculating the appropriate scattered ray direction.

Open your src/material.h file and add the dielectric class after the metal class. Make sure you've included math_utils.h at the top of the file if you haven't already. Here's the complete dielectric class:

Let's walk through this implementation step by step, understanding each decision and how it contributes to realistic glass rendering. The constructor takes a single parameter, the index of refraction, which we store in the member variable ir. We use the explicit keyword to prevent implicit conversions from double to dielectric, which is good practice for single-parameter constructors. The index of refraction characterizes the material: 1.5 for typical glass, 1.33 for water, 2.4 for diamond, and so on.

The scatter function begins by setting the attenuation to white . This represents the fact that ideal glass doesn't absorb any light as it passes through. In reality, glass does absorb some light, especially over long distances, and colored glass absorbs different wavelengths differently. However, for the thin glass objects we typically render in ray tracing, the absorption is negligible, so we use white attenuation. This means the glass doesn't change the color of light passing through it, only its direction.

Rendering Glass Objects and the Hollow Sphere Trick

With our dielectric material implemented, we're ready to create scenes featuring glass and other transparent objects. Let's set up a scene that demonstrates the various properties of dielectric materials, including refraction, reflection, and total internal reflection. We'll create several spheres with different materials to show how glass interacts with both diffuse and metallic surfaces, and we'll introduce a clever technique for creating hollow glass objects that look particularly realistic.

Open your src/main.cc file and update the scene setup section. We'll create a scene with a ground plane, a glass sphere in the center, a metal sphere on the right, and another glass sphere on the left. Here's the material and world setup:

Let's examine each material and object. The ground material is a Lambertian diffuse material with a yellowish color, the same as in previous lessons. This provides a matte surface that contrasts nicely with the shiny glass and metal spheres. The glass material is a dielectric with refractive index 1.5, which is typical for common glass. This will give us realistic glass behavior with the right amount of refraction and reflection. The metal material is a golden-colored metal with zero fuzz, creating a perfect mirror finish that will show clear reflections of the glass spheres.

The world setup includes five spheres. The first is the large ground sphere with radius one hundred, positioned below the scene to act as a flat ground plane. The second sphere is at the center of the scene with radius 0.5, made of glass. This is where things get interesting. The third sphere is also at the center of the scene, but it has a negative radius of -0.45 and is also made of glass. This negative radius creates what we call a hollow glass sphere, and it's a clever trick that produces particularly realistic glass objects.

How does a negative radius work? In our ray tracer, when we calculate ray-sphere intersections, a negative radius effectively flips the surface normal. The sphere still occupies the same space, but the normals point inward instead of outward. When we place a negative-radius sphere inside a positive-radius sphere at the same center, we create a hollow shell. Rays entering the outer sphere will eventually hit the inner sphere, but because the inner sphere's normals point inward, the ray tracer treats this as exiting the glass back into air (or rather, into the hollow interior, which we treat as air). This creates a glass bubble or hollow glass sphere.

Summary and What's Next

In this lesson, you learned how to render transparent materials like glass and water by implementing dielectric materials in your ray tracer. You explored the physics of refraction using Snell’s Law, handled total internal reflection when light cannot exit a material, and used Schlick’s approximation to simulate the Fresnel effect, which controls the balance between reflection and refraction based on viewing angle. You combined these concepts in a dielectric material class that probabilistically chooses between reflection and refraction for each ray. You also learned the hollow sphere trick to create realistic thin-walled glass objects. With diffuse, metal, and dielectric materials now implemented, your ray tracer can render a wide range of realistic scenes with complex material interactions.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal