Chapter 33: Fresnel and Beer's Law

Schlick’s Approximation

Schlick’s Approximation is a commonly used approximation for the Fresnel equations.

Where is the reflectance at normal incidence, given by:

Where is the material’s index of refraction.

This is similar to the Fresnel contribution we had for Cook-Torrance, instead here we use the normal vector instead of halfway vector. Remember that in Cook-Torrance, we summing contributions from microfacets with microsurface normal to the halfway vector. In this case we are only concerned with the macrosurface normal.

Beer’s Law

Given distance travelled through a medium , for object with color :

Where is a constant that we will arbitrarily define in this class:

We then multiply the color gathered by the refracted/transmitted ray by attenuation:


We have a handful of new .pov material constants as well as secondary rays which must now contribute to our final rendered color.

For this iteration of the class we will use the following (somewhat arbitrarily decided) system for determining the final color.

First we define the three computed colors:

In addition we have the following material properties:

As relection increases, we need to show more reflected light and as a result, less local light. Similarly, as filter increases, we need to show more refracted light and as a result, less local and reflected light.

Things get a little complicated when we throw Schlick’s Approximation into the mix, because now our “refracted light” can also include a reflected component.

This is the model we will use to scale the three light contributions:


We will first split our total light into the “filter” and “non-filter” sides. On the “filter” side, we have our transmitted light and some reflected light (as described by the Schlick’s Approximation). On the “non-filter” side, we will have our local shading computation as well as the reflected light as specified by the .pov material.

r // reflection vector
pt // intersection point

local_color := blinn_phong(n, l, v) // or cook_torrance
reflection_color := raytrace(pt + r * epsilon, r)
transmission_color := raytrace(pt + t * epsilon, t)

fresnel_reflectance := schlicks_approximation(ior, n, v)
local_contribution = (1 - finish.filter) * (1 - finish.reflection)
reflection_contribution = (1 - finish.filter) * (finish.reflection) + (finish.filter) * (fresnel_reflectance)
transmission_contribution = (finish.filter) * (1 - fresnel_reflectance)

total_color :=
    local_contribution * local_color +
    reflection_contribution * reflection_color +
    transmission_contribution * transmission_color