This chapter links to the course’s interactive demos and to original
papers on the open web, and it uses MathJax for its formulas. Read it
through the course website (or download the file and open it in a
browser); a Canvas inline preview will reach neither the demos nor the
math. All chapters.
Light Transport and PBR
Radiosity came to graphics from heat-transfer engineering, in the same 1984 paper that introduced the Cornell box.
Goral, Torrance, Greenberg and Battaile, SIGGRAPH 1984
The illumination chapter computes a point’s color from the lights, the normal, and the eye, and nothing else in the scene. This chapter writes down the equation that balances the light energy instead, the rendering equation, reads it term by term in the radiometric units of the color chapter, and rebuilds the material term on physical foundations: the BRDF and its two laws, microfacets with the exact Fresnel equations for glass and for gold, the furnace test that measures how much energy a model loses, and the two sliders every modern engine exposes. It then does what a renderer must do with such a model: draw directions from it, evaluate it under a whole sky by the split-sum trick, and extend it past opaque surfaces to glass and skin. Every formula is evaluated by hand at least once, and every figure is computed from the same formulas. The history, from Whitted’s rays to Kajiya’s equation, is in the history chapter; the algorithms that solve the equation are in the ray-tracing chapter.
A local illumination model (Phong, as the illumination chapter builds it) lights a
point from the lights, the normal, and the eye, and nothing else in the
scene; the ambient constant stands in for all the light that bounces.
Three things follow that no patch can fix.
It can reflect more light than arrives. Nothing in \(k_d\), \(k_s\) and the exponent \(s\) is tied to energy; Section 3 computes how much a plain Phong lobe can over-reflect.
It is not symmetric. Swapping the light and the eye should leave the amount of reflected light unchanged (Helmholtz reciprocity); the Phong specular term does not promise it.
It has no indirect light. The red wall of the Cornell box tints the white box beside it in a photograph and in a path-traced render (the ray-tracing chapter renders one); a local model paints the box white and adds a constant.
They are one gap: the local model never balances the light energy at a
point. The equation that does was written down by Kajiya in 1986
(the history chapter).
2 · Radiance, and the rendering equation term by term
The equation is a statement about radiance, so the unit comes
first. The color chapter defines the
radiometric quantities; three of them appear here. Radiant flux
is power, in watts. Irradiance \(E\) is the flux arriving per
unit area of a surface, in watts per square meter; it is what a light
meter held against the surface reads, and it already includes the
cosine factor, because a beam at a grazing angle spreads its watts over
more square meters (Lambert’s
argument). Radiance \(L\) is flux per unit area per unit
solid angle, in watts per square meter per steradian: the amount of
light traveling along one ray, in one direction, through one small
patch. Radiance is the quantity a camera pixel or a retinal cell
measures, it does not change along a ray through empty space, and it is
what a renderer computes for every pixel. The two are related by the
cosine: the irradiance at a point is the incoming radiance summed over
the hemisphere with each direction weighted by \(\mathbf{n}\cdot\omega_i\),
\(E = \int_\Omega L_i(\omega_i)\,(\mathbf{n}\cdot\omega_i)\,d\omega_i\).
The vocabulary of one point. \(\Omega\) is the hemisphere above \(\mathbf{x}\); \(\omega_i\) is any direction light can arrive from, \(\omega_o\) the direction toward the eye, \(\mathbf{h}\) the unit vector halfway between them. A microfacet reflects \(\omega_i\) into \(\omega_o\) exactly when its normal is \(\mathbf{h}\), which is why \(\mathbf{h}\) appears in every microfacet term of Section 4.
Definition (the rendering equation)
With \(\omega_o\) the direction toward the eye, \(\omega_i\) a direction light arrives from, and \(\mathbf{n}\) the surface normal,
\[
L_o(\mathbf{x}, \omega_o) \;=\; L_e(\mathbf{x}, \omega_o) \;+\;
\int_{\Omega} f_r(\mathbf{x}, \omega_i, \omega_o)\, L_i(\mathbf{x}, \omega_i)\,
(\mathbf{n}\cdot\omega_i)\, d\omega_i .
\]
Read it in words, one factor at a time.
Symbol
Name
Meaning
\(L_o(\mathbf{x},\omega_o)\)
outgoing radiance
the light leaving \(\mathbf{x}\) toward the eye: the number the pixel will show
\(L_e(\mathbf{x},\omega_o)\)
emitted radiance
nonzero only on light sources; the ceiling panel of the Cornell box
\(L_i(\mathbf{x},\omega_i)\)
incoming radiance
the light arriving at \(\mathbf{x}\) from direction \(\omega_i\); it is some other point’s \(L_o\)
\(f_r\)
BRDF
the material: what fraction of light from \(\omega_i\) leaves toward \(\omega_o\) (Section 3)
\(\mathbf{n}\cdot\omega_i\)
cosine factor
light arriving at a grazing angle is spread over more surface, so each unit of surface gets less
\(\int_\Omega \dots d\omega_i\)
the hemisphere integral
add up the contributions of every incoming direction
It is hard for one reason: \(L_i\) on the right is some other
point’s \(L_o\). Light bounces, so the equation refers to itself,
and the unknown appears on both sides. That self-reference is exactly
the indirect light the local model lacks: the red wall’s \(L_o\)
is the white box’s \(L_i\).
Worked example (the integral as a sum)
Replace the continuous sky by three small distant lights, so the
integral becomes a sum, and take a matte (Lambertian) surface with
albedo \(\rho = 0.6\), whose BRDF is the constant \(f_r = \rho/\pi = 0.191\)
(Section 3 says why the \(\pi\) is there). The point does not emit.
light
\(L_i\)
angle to \(\mathbf{n}\)
\(\mathbf{n}\cdot\omega_i\)
\(f_r\, L_i\, (\mathbf{n}\cdot\omega_i)\)
1
2.0
20°
0.940
\(0.191\times2.0\times0.940 = 0.359\)
2
0.8
60°
0.500
\(0.191\times0.8\times0.500 = 0.076\)
3
0.5
75°
0.259
\(0.191\times0.5\times0.259 = 0.025\)
\(L_o\)
0.460
Two things to notice. The cosine factor, not the BRDF, is what makes
light 3 nearly irrelevant: it is grazing. And \(L_o\) does not depend on
\(\omega_o\) at all, because a Lambertian BRDF is constant; that is the
definition of matte. Add a glossy term and the third column would gain a
factor that peaks near the mirror direction of each light. The three
lights carry the units too: if \(L_i\) is in watts per square meter per
steradian and each light subtends a small solid angle \(\Delta\omega\),
the sum is really \(\sum f_r L_i (\mathbf{n}\cdot\omega_i)\,\Delta\omega\),
and the table has set every \(\Delta\omega\) to 1.
3 · The BRDF, its laws, and why Phong is not one
Definition (BRDF)
The bidirectional reflectance distribution function
\(f_r(\omega_i, \omega_o)\) is the ratio of the radiance leaving toward
\(\omega_o\) to the irradiance arriving from a small cone around
\(\omega_i\). Its units are inverse steradians. A physically valid BRDF
satisfies two laws:
Energy conservation: for every \(\omega_o\), \(\int_\Omega f_r(\omega_i,\omega_o)\,(\mathbf{n}\cdot\omega_i)\,d\omega_i \le 1\). A surface cannot reflect more than it receives.
The integral in the second law is the directional albedo \(E(\omega_o)\): the fraction of light arriving from a uniform sky that leaves toward \(\omega_o\), or by reciprocity, the fraction of light arriving from \(\omega_o\) that leaves at all. Section 6 measures it.
The simplest BRDF is the constant one. If a matte surface reflects a
fraction \(\rho\) of the light it receives, equally in all directions,
then the energy law forces \(f_r = \rho/\pi\), because
\(\int_\Omega (\mathbf{n}\cdot\omega_i)\,d\omega_i = \pi\) (the cosine
integrated over the hemisphere). That is where the \(\pi\) in the
worked example above came from, and it is a first sign of the
difference between an ad hoc model and a physical one: in Phong,
\(k_d\) is a free number; here, \(\rho/\pi\) is a number tied to a law.
Worked example (how much light a Phong lobe reflects)
Take the Phong specular term with \(k_s = 1\) and exponent \(s\), light
arriving straight down the normal, and ask how much of it leaves in
total. The mirror direction is then the normal itself, so the lobe is
\(\cos^s\theta\) and the outgoing energy is
\[
\int_\Omega \cos^s\theta \,\cos\theta\, d\omega \;=\;
2\pi \int_0^{\pi/2} \cos^{s+1}\theta \,\sin\theta\, d\theta \;=\; \frac{2\pi}{s+2}.
\]
\(s\)
1
4
8
32
128
reflected / arriving
2.094
1.047
0.628
0.185
0.048
A broad lobe (\(s \le 4\)) sends out more light than came in; a sharp
one sends out almost none. Neither is what a real material does.
“Normalized Phong” fixes this by multiplying the lobe by
\((s+2)/2\pi\), and that normalization is the first step toward the
physically based models below: a BRDF whose brightness and width are
tied together, so an artist who makes a highlight sharper automatically
makes it brighter, as a real surface does.
3.1 Measured BRDFs
A BRDF need not be a formula. A gonioreflectometer holds a flat
sample, a light and a detector on motorized arms, and records the
reflected radiance for every pair of directions; the MERL database
(Matusik and others, 2003) did this for 100 materials at
\(90\times90\times180\) direction pairs each, about 1.5 million values
per color channel per material. A renderer can look such a table up
directly, interpolating between samples, and it is the ground truth
against which the analytic models below are judged: the model of
Section 4 fits the measured metals and plastics well, and fails on
fabrics and on layered materials (car paint, iridescent shells), which
is why those get models of their own. The lesson to keep: a BRDF is a
function of four angles that can be measured, and any formula is an
approximation of a measurement.
4 · Microfacets: D, G and F
Physically based rendering (PBR) models a rough surface as a field of
microscopic mirrors, the microfacets. Light arriving from
\(\omega_i\) leaves toward \(\omega_o\) only off the facets whose normal
is the half-vector \(\mathbf{h}\); the rest reflect elsewhere, are
shadowed, or shadow their neighbors. The Cook–Torrance specular
BRDF collects those three effects into three factors:
Definition (Cook–Torrance specular BRDF)
\[
f_r^{\text{spec}}(\omega_i,\omega_o) \;=\; \frac{D(\mathbf{h})\, G(\omega_i,\omega_o)\, F(\omega_i,\mathbf{h})}
{4\, (\mathbf{n}\cdot\omega_i)(\mathbf{n}\cdot\omega_o)} ,
\]
where \(D\) is the fraction of facets facing \(\mathbf{h}\) (the
normal distribution), \(G\) the fraction of those not shadowed
or masked, \(F\) the fraction of light a facet actually reflects
(Fresnel), and the denominator converts from facet area to
surface area.
4.1 D: where the facets point
The modern default is GGX (also called Trowbridge–Reitz), with a
single roughness parameter \(\alpha\):
\[
D(\mathbf{h}) \;=\; \frac{\alpha^2}{\pi\,\big((\mathbf{n}\cdot\mathbf{h})^2(\alpha^2 - 1) + 1\big)^2}.
\]
Left: \(D\) for four roughnesses. At \(\alpha = 0.1\) the peak is 31.8 and the curve has dropped below 0.01 by 25°; at \(\alpha = 1\) every facet direction is equally likely and \(D = 1/\pi\) everywhere. The area under each curve (weighted by the cosine) is 1: \(D\) is a distribution, and that is the normalization Phong lacked. Right: Schlick’s Fresnel curve. Plastic reflects 4 % head-on and 41 % at 80°; iron starts at 56 %; every material reaches 100 % at grazing.
The same three sharpness levels as lobes around the mirror direction, each normalized to 1 at the peak. GGX keeps a longer tail than a cosine power of the same peak width, which is the visible difference between a Phong highlight (a bright dot with a hard edge) and a GGX one (a dot with a halo). This is the plot the BRDF-lobes demo draws.
4.2 G: shadowing and masking
Facets hide one another. \(G\) is the fraction of facets that are both
lit (not shadowed from \(\omega_i\)) and visible (not masked from
\(\omega_o\)); the Smith form assumes the two are independent and
multiplies one factor per direction. For GGX the exact per-direction
factor is
Near the normal \(G_1 \approx 1\); at grazing angles on rough surfaces
it falls toward 0, which is what keeps the denominator’s
\(1/(\mathbf{n}\cdot\omega)\) from blowing up at the silhouette.
4.3 F: Fresnel
A dielectric reflects a few percent head-on and almost everything at
grazing incidence (look along a table top toward a window). Schlick’s
approximation captures it with one number per material, the reflectance
at normal incidence \(F_0\):
The table is the physics behind the metallic slider. Every dielectric
has nearly the same gray \(F_0\) of about 0.04 and gets its color from
light that enters the surface, scatters, and leaves diffusely. A metal
has a large, colored \(F_0\) and no diffuse term at all, because the
conduction electrons absorb whatever is not reflected. Where the
numbers come from is Section 5.
Worked example (a full evaluation)
Put the normal along \(z\), the light at \(30^\circ\) on one side and
the eye at \(30^\circ\) on the other, a plastic (\(F_0 = 0.04\)) with
\(\alpha = 0.3\).
Compare the Lambertian term of a mid-gray plastic, \(0.6/\pi = 0.191\):
at the mirror direction the highlight adds about a quarter of the
diffuse value. Now move the light out to \(45^\circ\), leaving the eye
at \(30^\circ\). Then \(\mathbf{h} = (-0.131, 0, 0.991)\), tilted
\(7.5^\circ\) from the normal; \(D\) drops to 2.574, \(G\) to 0.971,
\(F\) rises slightly to 0.0404, and
\(f_r^{\text{spec}} = 0.0412\). And at the original geometry with a
rougher surface, \(\alpha = 0.6\): \(D = 0.884\), \(G = 0.944\),
\(f_r^{\text{spec}} = 0.0111\), a quarter of the smooth value. The
highlight got dimmer as it got wider, with no separate brightness knob
to set: that is energy conservation doing the artist’s bookkeeping.
Hands-on
The three factors are ten lines of code. Run each from a terminal with node -e (paste the whole snippet as the argument), or in the browser console.
Evaluate the BRDF at a geometry the text did not: light at \(20^\circ\) on one side, eye at \(50^\circ\) on the other, \(\alpha = 0.3\), plastic.
Expected output: h angle 15.0 D 1.2571 f 0.02022. The half-vector sits halfway between the two directions, \(15^\circ\) off the normal, and the highlight is less than half the mirror-configuration value 0.0465.
Check the Phong energy table by numerical integration instead of the closed form:
let s=0;const N=2000;for(let i=0;i<N;i++){const th=(i+0.5)/N*Math.PI/2;
s+=Math.cos(th)**32*Math.cos(th)*Math.sin(th)*(Math.PI/2/N);}
console.log((2*Math.PI*s).toFixed(4),'vs',(2*Math.PI/34).toFixed(4));
Expected: 0.1848 vs 0.1848. Change 32 to 4 and the integral exceeds 1.
In the BRDF-lobes demo, set roughness to 0.3 and switch the model between Phong and GGX: the GGX lobe keeps the skirt the figure above shows, and the teapot’s highlight gains a halo.
5 · Fresnel exactly: dielectrics and conductors
Schlick’s curve is a fit. The quantity it fits is given exactly by
Fresnel’s equations, which follow from the wave theory of light at a
boundary between two media, and knowing them explains the \(F_0\)
table, tells where the fit is wrong, and separates the two kinds of
material by physics rather than by slider.
Fresnel’s equations
Light arriving at angle \(\theta_i\) from a medium of refractive index
\(n_1\) onto one of index \(n_2\) refracts at \(\theta_t\) with
\(n_1\sin\theta_i = n_2\sin\theta_t\) (Snell, as in
the ray-tracing chapter) and reflects
a fraction that depends on the polarization:
\[
\begin{gathered}
R_s = \left(\frac{n_1\cos\theta_i - n_2\cos\theta_t}{n_1\cos\theta_i + n_2\cos\theta_t}\right)^{2}, \qquad
R_p = \left(\frac{n_1\cos\theta_t - n_2\cos\theta_i}{n_1\cos\theta_t + n_2\cos\theta_i}\right)^{2}, \\[4pt]
F = \tfrac12 (R_s + R_p)
\end{gathered}
\]
for unpolarized light. At normal incidence both reduce to
\(F_0 = \big((n_1 - n_2)/(n_1 + n_2)\big)^2\). A conductor has a
complex index \(n + ik\), whose imaginary part \(k\) is absorption; the
same formulas apply with complex arithmetic, and at normal incidence
\(F_0 = \big((n-1)^2 + k^2\big)/\big((n+1)^2 + k^2\big)\).
Worked example (glass at 60°, exactly)
Air to glass, \(n_2 = 1.5\): \(F_0 = (0.5/2.5)^2 = 0.04\), the table’s
default. At \(\theta_i = 60^\circ\): \(\sin\theta_t = 0.866/1.5 = 0.577\),
\(\cos\theta_t = 0.8165\);
\(R_s = \big((0.5 - 1.5\cdot0.8165)/(0.5 + 1.5\cdot0.8165)\big)^2 = (0.7247/1.7247)^2 = 0.1766\);
\(R_p = \big((0.8165 - 0.75)/(0.8165 + 0.75)\big)^2 = (0.0665/1.5665)^2 = 0.0018\);
\(F = 0.0892\). Schlick gives \(0.04 + 0.96\,(0.5)^5 = 0.0700\), 21 % low.
The two polarizations differ by a factor of a hundred here: at
Brewster’s angle \(\arctan 1.5 = 56.3^\circ\), \(R_p\) is exactly zero,
which is why polarized sunglasses remove the glare off water and glass
near that angle. The table below is the whole curve.
\(\theta_i\)
0°
30°
45°
56.3°
60°
75°
85°
\(R_s\)
0.040
0.058
0.092
0.148
0.177
0.399
0.732
\(R_p\)
0.040
0.025
0.009
0.000
0.002
0.107
0.493
exact \(F\)
0.040
0.042
0.050
0.074
0.089
0.253
0.613
Schlick
0.040
0.040
0.042
0.057
0.070
0.255
0.649
Left: glass. Schlick underestimates the middle angles and slightly overestimates the last few degrees; the polarizations split widely, and the average is what an unpolarized renderer uses. Right: gold, from its measured complex index \(n = (0.143, 0.374, 1.442)\), \(k = (3.983, 2.386, 1.603)\) at red, green and blue wavelengths. \(F_0 = (0.967, 0.803, 0.324)\), close to the table’s \((1.00, 0.71, 0.29)\); the blue channel’s rise toward grazing is why gold looks whiter at the rim.
Worked example (gold at normal incidence)
Red channel: \(n = 0.143\), \(k = 3.983\):
\(F_0 = \big((0.143-1)^2 + 3.983^2\big)/\big((0.143+1)^2 + 3.983^2\big) = (0.734 + 15.86)/(1.306 + 15.86) = 0.967\).
Blue: \(n = 1.442\), \(k = 1.603\): \((0.195 + 2.570)/(5.963 + 2.570) = 0.324\).
A metal’s color is set by how its absorption varies with wavelength,
and the reflected light is tinted because \(F_0\) is; a dielectric’s
\(F_0\) hardly varies with wavelength (glass’s index changes by
about 1 % across the visible range), so its reflection is white and
its color must come from what happens under the surface.
So the two material recipes of Section 7 are not a convention. A
dielectric has real \(n\) near 1.5, \(F_0 \approx 0.04\), and transmits
what it does not reflect into a body that scatters it back diffusely.
A conductor has large \(k\), colored \(F_0\) of 0.5 to 1, and absorbs
within a few nanometers what it does not reflect, so it has no
diffuse term. Everything in between (a dusty chrome, a metallic paint
with flakes in a clear binder) is a mixture of the two kinds over the
area of a pixel.
6 · Energy: the furnace test and multiple scattering
The energy law of Section 3 is a promise; the furnace test
checks it. Put a surface with \(F = 1\) (a perfect mirror facet,
nothing absorbed) inside a uniformly lit white sphere, a furnace. A
model that conserves energy renders it invisible: it reflects
everything, so it is exactly as bright as its surroundings. The
directional albedo \(E(\omega_o) = \int f_r (\mathbf{n}\cdot\omega_i)\,d\omega_i\)
is that brightness, and the figure below computes it for the GGX
model by drawing 20,000 directions per point from the distribution of
Section 8.
The furnace test for GGX with Smith \(G\) and \(F = 1\). At \(\alpha = 0.1\) the model returns 99 % of the light; at \(\alpha = 0.5\), 68 % head-on; at \(\alpha = 1\), 30 % head-on and 38 % on average over the hemisphere. The missing energy is not absorbed by any physics in the model. It is light that bounced off one facet onto another, which the single-scattering model discards because \(G\) counts a shadowed facet as lost.
Worked example (how much a rough surface loses)
At \(\alpha = 1\), \(\mathbf{n}\cdot\omega_o = 1\), the albedo is 0.302: a
perfectly reflective, very rough surface renders at 30 % brightness,
70 % darker than it should. The average over the hemisphere is 0.379,
62 % lost. At \(\alpha = 0.5\) the average is 0.691, 31 % lost. Rough
metals rendered with the plain model are visibly too dark, and the
darkening grows with roughness, so a roughness texture also becomes a
darkness texture, which no artist asked for.
The fix is multiple-scattering compensation (Kulla and Conty,
2017; Turquin, 2019). The energy lost from a single bounce is
\(1 - E(\omega_o)\); a second lobe, shaped so that it integrates to
exactly that missing fraction and weighted by the average Fresnel
reflectance (a metal returns almost all of the inter-facet light, a
dielectric only a few percent of it), is added to the BRDF, and the sum
passes the furnace test to within a percent. The tables of \(E\) that
the compensation needs are precomputed once per roughness and viewing
angle; the figure above is that table’s first row. The same test
catches a second, older sin: the diffuse and specular terms of a
dielectric must share the energy, so the diffuse lobe of a physically
careful model is scaled by \(1 - F\), or by \(1 - E_{\text{spec}}\), rather
than added at full strength.
7 · Metallic and roughness, and the principled model
Every engine exposes the model above through two artist sliders on top
of a base color:
roughness sets \(\alpha\) (most engines use \(\alpha = \text{roughness}^2\) so that the slider feels linear; Unity’s smoothness is \(1 - \) roughness);
metallic blends between two material recipes. At 0 the surface is a dielectric: a diffuse term \(\text{base}/\pi\) under a weak white specular with \(F_0 = 0.04\). At 1 it is a metal: no diffuse term and a specular with \(F_0 = \text{base}\).
\[
f_r \;=\; (1 - m)\,\frac{\text{base}}{\pi} \;+\; f_r^{\text{spec}}\big(F_0 = (1-m)\,0.04 + m\,\text{base}\big).
\]
The model of this chapter, rendered by a forty-line ray marcher in the figure generator: one directional light plus a two-tone environment (bright sky above the horizon, dark ground below), Lambert diffuse, GGX \(D\), Smith \(G\), Schlick \(F\), gamma 2.2. Across: roughness 0.1, 0.3, 0.5, 0.7, 0.9. Down: metallic 0, 0.25, 0.5, 0.75, 1. The dielectric row keeps its base color in the shadow side, because the diffuse term is there; the metal row goes dark except where it reflects the light and the sky, and those reflections are tinted by the base color, because \(F_0\) is. The horizon line visible on the plastic spheres is real: Fresnel makes even plastic a weak mirror.
These are the sliders in Unity’s Standard Shader, and the same
parameterization is what glTF and every modern renderer exchange. That
agreement is the practical result of PBR: a material authored once
looks the same in every engine, under any lighting, because the numbers
mean physical things rather than tuning constants for one scene.
Pitfall
Two mistakes that survive in shipped shaders, with their size.
Using the roughness slider as \(\alpha\) directly. At roughness 0.5 the peak of \(D\) is \(1/(\pi\alpha^2)\): \(1.27\) with \(\alpha = 0.5\), \(5.09\) with \(\alpha = 0.25\), the engine’s convention. A material exported from an engine that squares and rendered by one that does not gets highlights four times too dim and twice too wide at the middle of the slider, and the two agree only at 0 and 1.
Trusting Schlick at middle angles for glass. From Section 5, Schlick is 21 % low at \(60^\circ\) and 23 % low at Brewster’s angle, and it cannot represent the polarization split at all. For opaque plastics the error is invisible under the diffuse term; for a glass window, a water surface or a clear coat, where the reflection is the whole appearance, the exact formula costs one square root and a division and should be used.
7.1 The principled model
Two sliders are not enough for every material, and the extension that
the film industry standardized is Disney’s principled BRDF
(Burley, 2012), built from the MERL measurements of Section 3 under
the rule that every parameter is a number between 0 and 1 with a
visible meaning. Its parameters, in the order an artist meets them:
parameter
what it controls
physics
baseColor
the surface color
diffuse albedo for dielectrics, \(F_0\) for metals
metallic
dielectric to conductor
the blend of Section 7
roughness
highlight width
\(\alpha = \text{roughness}^2\) in GGX, for both lobes
specular, specularTint
strength and color of the dielectric reflection
\(F_0\) from 0 to 0.08, optionally tinted toward the base color
anisotropic
stretched highlights
two roughnesses along the tangent and bitangent (brushed metal, hair)
sheen, sheenTint
soft glow at grazing angles
a retro-reflective lobe for cloth
clearcoat, clearcoatGloss
a second, thin glossy layer
a fixed-index (1.5) dielectric lobe over the base: car paint, lacquer
subsurface
light that enters and leaves nearby
a blend toward a subsurface-like diffuse lobe (Section 10)
glTF’s material model is a subset of this table (base color,
metallic, roughness, plus extensions for clear coat, sheen and
transmission), and Blender’s Principled BSDF is the whole of it.
See it liveBRDF lobes:
the course’s Cornell scene with four material identities (a gold
metal teapot, an aluminum metal box, a pastel plastic bunny, a glossy
dielectric box) all wearing one plotted BRDF. Drop roughness and every
highlight tightens toward a mirror while the inset lobe needles; switch
Phong to GGX to compare the tails. The two mappings from roughness to
lobe width are not calibrated to each other; the demo shows shape, not
units.
8 · Sampling the BRDF
A path tracer (the ray-tracing
chapter) estimates the hemisphere integral by drawing random
directions and averaging \(f_r L_i (\mathbf{n}\cdot\omega_i)/p(\omega_i)\).
Uniform directions waste nearly every sample on a glossy surface, whose
\(f_r\) is negligible except near the mirror direction. The remedy is to
draw directions from the BRDF’s own shape, and GGX was chosen partly
because its \(D\) can be inverted in closed form.
Sampling GGX
Draw a facet normal \(\mathbf{h}\) from \(D(\mathbf{h})(\mathbf{n}\cdot\mathbf{h})\), which is a probability density over the hemisphere, with two uniform numbers \(u_1, u_2 \in [0,1)\):
\[
\cos\theta_h = \sqrt{\frac{1 - u_1}{1 + (\alpha^2 - 1)\,u_1}}, \qquad \phi_h = 2\pi u_2,
\]
then reflect the view direction about it, \(\omega_i = 2(\omega_o\cdot\mathbf{h})\,\mathbf{h} - \omega_o\). The density of the resulting direction is \(p(\omega_i) = D(\mathbf{h})(\mathbf{n}\cdot\mathbf{h}) / \big(4\,(\omega_o\cdot\mathbf{h})\big)\), and the estimator’s weight simplifies:
\[
\frac{f_r\,(\mathbf{n}\cdot\omega_i)}{p(\omega_i)} \;=\; \frac{F\,G\,(\omega_o\cdot\mathbf{h})}{(\mathbf{n}\cdot\omega_o)(\mathbf{n}\cdot\mathbf{h})}.
\]
\(D\) cancels: the sampler already accounted for it.
Worked example (one sample)
\(\alpha = 0.3\), the eye at \(30^\circ\) from the normal,
\(\omega_o = (0.5, 0, 0.866)\), random numbers \(u = (0.3, 0.25)\).
\(\cos\theta_h = \sqrt{0.7/(1 - 0.91\cdot0.3)} = \sqrt{0.7/0.727} = 0.9813\),
\(\theta_h = 11.1^\circ\), \(\phi_h = 90^\circ\), so
\(\mathbf{h} = (0, 0.193, 0.981)\). Then \(\omega_o\cdot\mathbf{h} = 0.850\)
and \(\omega_i = 2(0.850)\,\mathbf{h} - \omega_o = (-0.500, 0.328, 0.802)\),
a direction \(36.7^\circ\) from the normal on the far side, sideways by
the facet’s tilt. \(D(\mathbf{h}) = 1.869\), \(p(\mathbf{h}) = 1.834\),
\(p(\omega_i) = 1.834/(4\cdot0.850) = 0.540\). The BRDF there is
\(f_r = 0.0264\) (with \(G = 0.981\), \(F = 0.040\)), and the weight is
\(0.0264 \times 0.802 / 0.540 = 0.0393\), the same as the short form
\(0.040\times0.981\times0.850/(0.866\times0.981) = 0.0393\). Averaged over
many such samples the weight converges to the directional albedo of
Section 6 times the average Fresnel, which is what the estimator is for.
Twenty thousand draws of \(\theta_h\) from the formula against the density \(D(\mathbf{h})\cos\theta_h\cdot2\pi\sin\theta_h\) they should follow. The match is the proof that the inversion is right; the tail past \(45^\circ\) is where GGX differs from a Gaussian lobe, and the sampler visits it in proportion.
Sampling \(D\) still wastes the draws that reflect below the horizon
(\(\mathbf{n}\cdot\omega_i < 0\)) and the ones that a facet would mask;
sampling the visible normals instead (Heitz, 2018) removes both
and is what production path tracers use. Diffuse lobes are sampled
with cosine-weighted directions, as in the ray-tracing chapter, and a
material with both lobes picks one per sample in proportion to its
albedo. The general principle, importance sampling, is the same
everywhere: draw from something shaped like the integrand, and divide
by its density.
9 · A whole sky at once: image-based lighting and the split sum
Real-time engines cannot integrate over the hemisphere per pixel, but
their light is often a whole environment: a captured panorama, or the
sky and ground of the sphere grid above. Image-based lighting
treats every texel of that panorama as a distant light. For the
diffuse term the integral is a blur of the environment by the cosine
lobe, precomputed once into a small map indexed by the normal. For the
specular term the integrand depends on the view direction and the
roughness as well, and the trick that made it affordable is the
split sum (Karis, 2013):
Definition (the split-sum approximation)
\[
\int_\Omega f_r\, L_i\,(\mathbf{n}\cdot\omega_i)\,d\omega_i \;\approx\;
\underbrace{\Big(\int_\Omega D\text{-weighted } L_i\, d\omega_i\Big)}_{\text{prefiltered environment}}
\cdot
\underbrace{\Big(\int_\Omega f_r\,(\mathbf{n}\cdot\omega_i)\,d\omega_i\Big)}_{F_0\,A + B}.
\]
The first factor is the environment blurred by the GGX lobe at each roughness, stored as the mip levels of a cube map and looked up along the reflected direction. The second is the directional albedo of Section 6 with Schlick’s Fresnel factored out, \(E = F_0 A(\mathbf{n}\cdot\omega_o, \alpha) + B(\mathbf{n}\cdot\omega_o, \alpha)\), stored as a two-channel \(32\times32\) texture that every material shares.
The BRDF integration table, computed here by importance sampling with 256 draws per texel: horizontal axis \(\mathbf{n}\cdot\omega_o\) from grazing (left) to head-on (right), vertical axis roughness from smooth (bottom) to rough (top); red is \(A\), green is \(B\). Every real-time engine carries this same picture.
Worked example (one table entry)
At \(\mathbf{n}\cdot\omega_o = 0.5\) (the surface seen at \(60^\circ\)) and
\(\alpha = 0.5\), 20,000 samples give \(A = 0.679\), \(B = 0.010\). For
plastic, \(E = 0.04\times0.679 + 0.010 = 0.037\): the environment
reflection is 3.7 % of the prefiltered radiance. For gold with
\(F_0 = (1.00, 0.71, 0.29)\), \(E = (0.689, 0.492, 0.207)\): the sky
reflects strongly and tinted. \(A + B = 0.689\) is the furnace albedo of
Section 6 at this angle and roughness (\(E = 0.68\) for \(\mathbf{n}\cdot\omega_o = 0.7\), \(0.71\) for \(0.4\)),
and the split has simply pulled \(F_0\) out of the integral.
What the approximation drops is the correlation between the
environment’s brightness and the BRDF’s shape inside the
integral: a bright sun just outside the lobe is treated as if the lobe
were centered on it. At high roughness and grazing angles the error is
visible as a slightly wrong reflection shape; it is the price of a
two-texture-lookup specular term, and the reason the sphere grid of
Section 7 could be rendered by a forty-line marcher with a blurred
two-tone sky rather than by a path tracer.
10 · Beyond opaque surfaces
The rendering equation as written integrates over the hemisphere
above the surface. Light also goes in.
Transmission. For glass, water and gems the BRDF gets a
partner, the BTDF, over the hemisphere below, and the two together (a
BSDF) share the energy through Fresnel: a fraction \(F\) reflects, and
\(1 - F\) refracts along the direction Snell gives, as the ray-tracing
chapter’s glass sphere does. A rough glass uses the same microfacet
machinery with refraction through each facet (Walter and others,
2007). Inside a colored medium the light is absorbed along its path by
the Beer–Lambert law, \(T = e^{-\sigma_a d}\), the same exponential
as the transmittance of the
learned-scenes chapter.
Worked example (colored glass)
A glass with absorption \(\sigma_a = (0.5, 2.0, 4.0)\) per centimeter in
red, green and blue. Through 1 cm the transmitted fractions are
\((e^{-0.5}, e^{-2}, e^{-4}) = (0.607, 0.135, 0.018)\): a red tint. Through
3 cm, \((0.223, 0.002, 0.000)\): a deep red that has lost all its blue.
Color in a transmissive medium depends on the path length, which is why
a glass bottle is darker at its thick base and why the same dye is pink
in a thin layer and red in a thick one.
Subsurface scattering. Skin, marble, wax, milk and
leaves are dielectrics whose “diffuse” term is not local:
light enters at one point, scatters many times in the body, and leaves
at another point some millimeters away. The Lambertian term of Section
3 is the limit in which that distance is zero. A subsurface model
replaces \(f_r\) by a function of two points as well as two
directions (a BSSRDF), and in practice by a diffusion profile: the
exiting light is the entering irradiance blurred over the surface with
a kernel whose width is the mean free path in the material. Skin’s
kernel is about a millimeter and reddish, because red light travels
farthest in tissue; the soft, warm look of a backlit ear is that blur.
Real-time engines approximate the blur in screen space; path tracers
random-walk inside the volume. The principled model’s subsurface
slider blends toward this behavior.
Participating media. Fog, smoke and clouds scatter
light everywhere along a ray rather than at a surface, and the
rendering equation becomes the volume rendering equation, with a
density, an absorption and a scattering phase function at every point.
That equation is the one the
learned-scenes chapter integrates along a ray, with the scattering
term replaced by a learned color; a NeRF is a participating medium that
has learned to look like a solid.
11 · Solving the equation: path tracing and real time
The rendering equation is an integral equation with the unknown on both
sides, so it is solved by iteration or by sampling. Path
tracing estimates the integral at a pixel by Monte Carlo:
shoot a ray, at the hit point pick a random \(\omega_i\) (from the
BRDF, as in Section 8), weight the bounce by \(f_r\,(\mathbf{n}\cdot\omega_i)\)
divided by the probability of having picked that direction, and recurse
until the path reaches a light or is terminated. Average many paths per
pixel and the noise falls as \(1/\sqrt{N}\). Every bounce is a sample of
the same integral, so indirect light, soft shadows, color bleeding and
caustics come out with no special cases; the price is hundreds of
samples per pixel. The
ray-tracing chapter builds the algorithm from its parts and renders
a Cornell box with it.
Real-time engines keep the local term (one BRDF
evaluation per light, exactly the worked example of Section 4) and
approximate the rest: the split sum of Section 9 for the sky,
screen-space or ray-traced reflections for the mirror term, and a
precomputed ambient-occlusion or irradiance volume for the diffuse
bounce. Since 2018 hardware ray tracing has moved parts of that list
back toward honest sampling, denoised, at a few samples per pixel.
Both routes evaluate the same \(f_r\); they differ in how much of the
hemisphere they can afford to look at.
Papers
J. Kajiya, “The Rendering Equation,” SIGGRAPH 1986. R. Cook and K. Torrance,
“A Reflectance Model for Computer Graphics,” ACM Transactions on Graphics 1(1), 1982.
B. Walter, S. Marschner, H. Li and K. Torrance, “Microfacet Models for Refraction through
Rough Surfaces,” Eurographics Symposium on Rendering 2007 (the GGX distribution and its sampling).
C. Schlick, “An Inexpensive BRDF Model for Physically-based Rendering,” Computer Graphics
Forum 13(3), 1994. W. Matusik, H. Pfister, M. Brand and L. McMillan, “A Data-Driven Reflectance
Model,” SIGGRAPH 2003 (the MERL database). B. Burley, “Physically Based Shading at
Disney,” SIGGRAPH 2012 course notes. B. Karis, “Real Shading in Unreal Engine 4,”
SIGGRAPH 2013 course notes (the split sum). C. Kulla and A. Conty, “Revisiting Physically
Based Shading at Imageworks,” SIGGRAPH 2017 course notes (multiple-scattering compensation).
E. Heitz, “Sampling the GGX Distribution of Visible Normals,” Journal of Computer Graphics
Techniques 7(4), 2018.
12 · Exercises
Exercise 1 (the cosine factor)
Redo the three-light example with the same lights but a darker surface,
\(\rho = 0.3\). Then move light 1 to \(70^\circ\). Which change reduced
\(L_o\) more?
Solution
Halving \(\rho\) halves everything: \(L_o = 0.230\). Moving light 1 to
\(70^\circ\) (with \(\rho = 0.6\) again) changes its cosine from 0.940
to 0.342, its term from 0.359 to 0.131, and \(L_o\) from 0.460 to 0.232,
about the same loss. A grazing angle costs as much as a surface half as
reflective.
Exercise 2 (D is a distribution)
Evaluate GGX \(D\) at \(\mathbf{n}\cdot\mathbf{h} = 1\) for \(\alpha = 0.1\)
and \(\alpha = 1\). Explain why the second is \(1/\pi\).
Solution
At \(\mathbf{n}\cdot\mathbf{h} = 1\) the bracket is
\((\alpha^2 - 1) + 1 = \alpha^2\), so \(D = \alpha^2/(\pi\alpha^4) = 1/(\pi\alpha^2)\):
31.8 for \(\alpha = 0.1\) and \(1/\pi = 0.318\) for \(\alpha = 1\). With
\(\alpha = 1\) the bracket is 1 for every \(\mathbf{h}\), so \(D\) is
the constant \(1/\pi\): all facet directions equally likely, and the
constant that integrates to 1 against the cosine over the hemisphere
is \(1/\pi\), the same constant as the Lambertian BRDF.
Exercise 3 (Fresnel at the rim)
For plastic (\(F_0 = 0.04\)), at what angle between \(\mathbf{v}\) and
\(\mathbf{h}\) does Schlick’s \(F\) reach 0.5? Compare with the exact
table of Section 5.
Solution
\(0.04 + 0.96\,(1 - c)^5 = 0.5\) gives \((1-c)^5 = 0.479\),
\(1 - c = 0.863\), \(c = 0.137\), an angle of \(82^\circ\). The exact
curve reaches 0.5 a little later, between \(75^\circ\) (0.253) and
\(85^\circ\) (0.613), near \(83^\circ\). Plastic is half a mirror only
within about seven degrees of grazing, which is why the reflection of
a window on a table top appears only when you look along the table.
Exercise 4 (Brewster)
Water has \(n = 1.33\). Compute \(F_0\), Brewster’s angle, and \(R_s\) at that angle.
Solution
\(F_0 = (0.33/2.33)^2 = 0.020\), the table’s value. Brewster: \(\arctan 1.33 = 53.1^\circ\), where \(\theta_i + \theta_t = 90^\circ\) so \(\cos\theta_t = \sin\theta_i = 0.800\). \(R_s = \big((0.600 - 1.33\cdot0.800)/(0.600 + 1.33\cdot0.800)\big)^2 = (0.464/1.664)^2 = 0.078\), and \(R_p = 0\): the reflection off a lake at \(53^\circ\) is entirely s-polarized, which a polarizing filter turned the right way removes completely.
Exercise 5 (metallic in between)
A slider value of metallic 0.5 is common in beginners’ materials.
Using the blend formula of Section 7, say what such a surface is
physically, and why real materials are almost always at 0 or 1.
Solution
It is half a dielectric and half a metal: a diffuse term at half
strength under a specular whose \(F_0\) is the average of 0.04 and the
base color. No homogeneous material behaves so, because Section 5
divides materials by whether \(k\) is negligible or large; the value is
meaningful only as an average over a surface that is partly metal and
partly not (dust on chrome, paint over steel), which is how texture
artists use it. A clean material is 0 or 1.
Exercise 6 (the furnace)
From the figure of Section 6, a rough gold (\(\alpha = 0.8\), \(F_0 \approx 0.9\)) seen head-on under a uniform sky of radiance 1. What does the single-scattering model render, and what should it render?
Solution
\(E(1, 0.8) = 0.421\), so the model returns \(0.9\times0.42 \approx 0.38\) of the sky’s radiance. A real gold surface returns nearly all the light that is not absorbed, and since each inter-facet bounce loses only 10 %, the true value is close to \(0.9\) minus a small multiple-bounce absorption, about 0.85. The render is less than half as bright as it should be; compensation adds the missing 0.47.
Exercise 7 (a sample by hand)
Repeat the sampling example with \(u = (0.9, 0.5)\) and \(\alpha = 0.3\). Where does the facet point, and where does the reflected direction go?
Solution
\(\cos\theta_h = \sqrt{0.1/(1 - 0.91\cdot0.9)} = \sqrt{0.1/0.181} = 0.743\), \(\theta_h = 42^\circ\), \(\phi_h = 180^\circ\): a facet tilted far over, toward the \(-x\) side, \(\mathbf{h} = (-0.669, 0, 0.743)\). \(\omega_o\cdot\mathbf{h} = -0.335 + 0.644 = 0.309\), and \(\omega_i = 2(0.309)\mathbf{h} - \omega_o = (-0.913, 0, -0.407)\): below the horizon. This sample is wasted (weight 0), which is the case the visible-normal sampler avoids; at \(\alpha = 0.3\) about a tenth of draws at this view angle end this way.
Exercise 8 (the split sum, with code)
Write a Monte Carlo estimate of the split-sum entry \((A, B)\) at \(\mathbf{n}\cdot\omega_o = 1\), \(\alpha = 0.1\), using the sampling formula of Section 8 and the weight \(G\,(\omega_o\cdot\mathbf{h})/((\mathbf{n}\cdot\mathbf{h})(\mathbf{n}\cdot\omega_o))\) split into \((1 - (1 - \omega_o\cdot\mathbf{h})^5)\) and \((1 - \omega_o\cdot\mathbf{h})^5\) parts. What should \(A + B\) be?
Solution
Head-on and nearly smooth, every sampled facet points nearly along the normal, \(\omega_o\cdot\mathbf{h} \approx 1\), the Fresnel factor \((1 - \omega_o\cdot\mathbf{h})^5 \approx 0\), and \(G \approx 1\): \(A \approx 0.99\), \(B \approx 0\), and \(A + B\) equals the furnace albedo \(E(1, 0.1) = 0.988\) from Section 6. The estimate converges to it within a percent at a few thousand samples; a run of the generator’s code with these parameters is the check.
Exercise 9 (transmission)
A stained-glass window is 4 mm thick with \(\sigma_a = (0.5, 2.0, 4.0)\) per cm as in Section 10. What color does white light become, and how thick must the glass be for the green channel to fall to 10 %?
Solution
\(d = 0.4\) cm: \((e^{-0.2}, e^{-0.8}, e^{-1.6}) = (0.819, 0.449, 0.202)\), an orange-red. Green at 10 %: \(e^{-2d} = 0.1\), \(d = \ln 10 / 2 = 1.15\) cm. Beer–Lambert is exponential, so each doubling of thickness squares the transmitted fraction.