layout: default title: (Task 5) Materials permalink: /pathtracer/materials parent: "A3: Pathtracer" has_children: false has_toc: false usemathjax: true


(Task 5) Materials

Walkthrough

Now that you have implemented the ability to sample more complex light paths, it's time to add support for more types of materials. In this task you will add support for two types of specular materials: mirrors and glass. These materials are implemented in student/bsdf.cpp.

First, take another at the BSDF interface in rays/bsdf.h. There are a number of key methods you should understand in BSDF:

To complete the mirror and glass materials, you will only need to implement their scatter functions, as they are both discrete BSDFs (i.e. they have a finite number of possible in_dirs for any out_dir). Additionally, you will want to complete two helper functions:

Finally, when working with Snell's law, there is a special case to account for: total internal reflection. This occurs when a ray hits a refractive boundary at an angle greater than the critical angle. The critical angle is the incident \theta_i that causes the refracted \theta_t to be >= 90 degrees, hence can produce no real solution to Snell's Law. In this case, you should set was_internal to true.

\eta_i \sin(\theta_i) = \eta_t\sin(\theta_t) \frac{\eta_i\sin(\theta_i)}{\eta_t} = \sin(\theta_t) \frac{\eta_i\sin(\theta_i)}{\eta_t}\overset{?}{\geq} 1


Step 1: BSDF_Mirror

Implement reflect and BSDF_Mirror::scatter().

Because discrete BSDFs do not require Monte Carlo integration (we can simply analytically evaluate each possible direction), we do not implement BSDF::pdf. Perhaps more interestingly, we also do not require BSDF::evaluate. This is because evaluating the BSDF is only necessary when sampling directions from distributions other than the BSDF itself. When the BSDF is discrete, like a perfect mirror, we can assume other distributions never sample the single (infinitesimal) direction at which the BSDF is non-zero.

Therefore, we must update our path tracing procedure in Pathtracer::sample_(in)direct_lighting: when the BSDF is discrete (BSDF::is_discrete), we are not doing a Monte Carlo estimate, hence should not use BSDF::pdf. Instead, simply multiply the scattering attenuation and the incoming light. Note that failing to make this check will cause the invalid BSDF calls to abort.

Step 2: BSDF_Glass

Implement refract and BSDF_Glass::scatter().

Glass is a material that can both reflect and transmit light. As discussed in class, the fraction of light that is reflected vs. transmitted is governed by the dielectric (non-conductive) Fresnel equations. To simulate this, we may sample in_dir from either reflection or refraction with probability proportional to the Fresnel reflectance. For example, if the Fresnel reflectance is 0.9, then you should generate a reflected ray 90% of the time. Note that instead of computing the full Fresnel equations, you have the option to use Schlick's approximation instead.

In the description below, \eta_i and \theta_i refer to the index of refraction of the medium containing the incoming ray and the angle of that ray with respect to the boundary surface normal. \eta_t and \theta_t refer to the index of refraction of the new medium and the angle to the boundary normal of the transmitted ray.

The Fresnel equations state that reflection from a surface is a function of the surface's index of refraction and the polarity of the incoming light. Since our renderer doesn't account for polarity, we'll apply a common approximation of averaging the reflectance of light polarized in perpendicular and parallel directions:

F_r = \frac{1}{2}(r^2_{\parallel}+r^2_{\perp})

The parallel and perpendicular terms are given by:

r_{\parallel} = \frac{\eta_t\cos(\theta_i) - \eta_i\cos(\theta_t)}{\eta_t\cos(\theta_i)+\eta_i\cos(\theta_t)} r_{\perp} = \frac{\eta_i\cos(\theta_i) - \eta_t\cos(\theta_t)}{\eta_i\cos(\theta_i)+\eta_t\cos(\theta_t)}

Therefore, for a dielectric material, the fraction of reflected light will be given by F_r, and the amount of transmitted light will be given by 1-F_r.

Alternatively, you may compute F_r using Schlick's approximation.

Distribution Function for Transmitted Light

Although we described the BRDF for perfect specular reflection in class, we did not discuss the distribution function for transmitted light. Unlike reflection, refraction "spreads" or "condenses" a differential beam of light. Hence, a refraction event should change the radiance along a ray.

After using Snell's Law to find the direction of refracted rays, compute the BSDF attenuation using the distribution function found in Pharr, Jakob, and and Humphries's book Physically Based Rendering. It also includes a derivation based Snell's Law and the relation d\Phi_t = (1-F_r)d\Phi_i. Of course, you are more than welcome to attempt a derivation on your own!


Tips


Reference Results

When you are done, you will be able to render images with specular materials, like the Cornell Box with a metal and glass sphere (cbox.dae, 1024 samples, max depth 8):


Extra Credit

Table of Content