There are a lot of PBR related writings out there which can make it very difficult to piece together the history and all of the different concepts into a complete PBR understanding. The goal of this short series is not to overload you with equations (those are easy enough to find) but to explain how they all come together for a PBR renderer.

PBR as we see it today usually consists of 2 parts:

- Computing diffuse and specular light reflection from punctual (i.e. direct) light sources
- Computing diffuse and specular light reflection from environment maps.

In this part of the series (Part 1) I’ll start with punctual light sources. Part 2 will cover environment maps, and Part 3 will cover where we’re headed next as real-time rendering starts to incorporate additional equations to handle light transmission and refraction.

Before we dive in, there’s one acronym I want to clarify: BRDF. If you’ve read at all about PBR you’ve most likely heard of BRDF, it stands for Bidirectional Reflectance Distribution Function. While it sounds complicated, it’s really just a general term for any equation used to compute the amount of light energy which is reflected off of a surface. The core of PBR is picking BRDFs for diffuse lighting and specular lighting which work across a wide variety of material types. These BRDFs must also be energy conserving, which simply means they don’t put out more energy than the incoming light contains.

Let’s start with the punctual light sources.

**Diffuse Light Reflection**

A BRDF which computes the diffuse light reflection from a punctual light source can be fairly trivial. Using Lambertian Diffuse is a generally accepted algorithm, however you can use more complicated ones with varying perf/quality trade offs. Taking this into our BRDF language we can say our BRDF for diffuse light reflection for punctual light sources can be as simple as the cosine of the light direction vector and the surface normal:

$$Fd(L,N) = BRDF(L,N) = L\cdot{N}$$

Fd in this example simply stands for Function for Diffuse, L is your light vector and N is the surface normal.

**Specular Light Reflection**

A BRDF which computes the specular light reflection from a punctual light source has become more complex over time as GPU processing power improves and the community is striving to have a single equation imitate real world specular reflections across a variety of materials. A widely used specular BRDF is known as the Cook-Torrence BRDF. Before I dive into the equation I’ll give a little background on the concept.

The Cook-Torrence BRDF is based on the concept that a surface is actually made up of millions of tiny microfacets, essentially tiny flat mirrors, which scatter the incoming light in different directions. The orientations of these microfacets relative to the surface direction vary greatly depending on surface properties such as roughness and conductivity. You can imagine a very flat smooth metallic surface would directly reflect light because its microfacets are all oriented in the same direction as the surface normal, whereas a very rough surface would have its microfacets oriented in any number of directions causing the light to scatter on the surface before some of it is reflected outward. In essence, this BRDF’s goal is to approximate the overal light reflected as if it really had bounced off of all the tiny microfacets. We refer to this as single scattering because it doesn’t account for more advanced light scattering simulations where the light will scatter within the surface of the object (we will touch on that in Part 3).

The Cook-Torrence specular BRDF consists of three separate algorithms: $$F(V,H) G(L,V,H) D(H)$$

\(F(V,H)\) computes the Fresnel reflection (how much of the light is reflected based on the light direction, the surface normal, and your viewing angle).

\(G(L,V,H)\) computes the geometric shadowing (how much of the light is not reflected because other microfacets are occluding it).

\(D(H)\) computes the distribution of the light over the microfacets and how much is reflected.

Combining all of these gives you how much specular light is reflected depending on:

- V (the view vector)
- L (the light vector)
- N (the surface normal)
- H (the half vector between the light vector and the surface normal)
- \(\frac{L+V}{|L+V|}\)

- The roughness of the surface
- The conductivity of the surface (metallic or dielectric)

The full Cook-Torrence specular BRDF is:

$$Fs(L,N,V) = BRDF(L,N,V) = \frac{F(V,H)G(L,V,H)D(H)}{4(N\cdot{V})(N\cdot{L})}$$

Fs in this example simply stands for Function for Specular. The next part is choosing the equations for F, G, and D.

**F** (the Fresnel reflection) is generally accepted as being Schlick’s Fresnel Approximation. Wikipedia has a straight forward explanation and I won’t elaborate on it here.

**G **(The shadowing function) depends on **D **(the distribution function), so we’ll address them together here. The algorithms you’ve probably heard most about are Beckmann Distribution and GGX. GGX was first published by Cornell in Eurographics 2008 (unfortunately its acronym is never addressed). I won’t speak to their specifics here but you can easily find them in the referenced links. However at a high level you send them L, V, H, and the roughness of the surface, They return an approximation of the overall light which would be reflected by the microfacets.

In many of the papers you will see the Microfacet normal referenced, usually as

m(this is the individual normal of each microfacet). We usually don’t have this information we only have the surface normal and the roughness; therefore it is approximated by substituting H (the half vector described above).

If you’ve read this far, you’ll now see that we have Fd which is our diffuse BRDF (Lambertian Diffuse) and Fs which is our single scattering specular BRDF (Cook-Torrence leveraging GGX or Beckmann) for punctual light sources.

To get the total energy of the reflected light you could add them together:

$$Energy = Fd(L,N) + Fs(L,N,V)$$

However, remember one of the key factors of PBR is to be energy conserving. Even if both our Fd and Fs are energy conserving, adding them together could result in a value greater than the incoming light; we need a way to make sure this doesn’t happen.

To do this we revisit our fresnel value in Fs. The fresnel value scales the amount of specular light depending on H (the half vector) and V (the view vector). We can then calculate the amount of diffuse light to incorporate based off of how much specular is used. To do this we’ll want to extract the fresnel from our Fs and compute it in advance.

$$fresnel = F(V,H)$$

Then our Fs becomes:

$$Fs= \frac{G(L,V,H)D(H)}{4(N\cdot{V})(N\cdot{L})}$$

Now we can scale the two BRDFs based off of the fresnel to conserve energy:

$$Energy = (1 – fresnel) * Fd(L,N) + fresnel * Fs(L,N,V)$$

Cool huh? Now our PBR correctly conserves energy while incorporating both the Diffuse BRDF and the Specular BRDF.

There is one more step required for this to be considered a modern day PBR algorithm, accounting for metallic surfaces. These surfaces simply reflect specular light and have no diffuse component. PBR algorithms use a metallic coeffecient [0, 1] to decrease the amount of diffuse lighting reflected from a material.

$$Energy = (1 – metallic) * (1 – fresnel) * Fd(L,N) + fresnel * Fs(L,N,V)$$

Nothing fancy there, ‘metallic’ is usually an artist driven parameter with the advice to keep it a binary value (1 = metallic, 0 = dielectric).

Once again, I didn’t go into any specific equations – I’m hoping I provided enough for the concept and the high level calculations to be understood and you can drop in whichever equations you desire for F, G, and D.

There is an important item to remember! These are just algorithms to approximate real light physics. There is no single solution and any PBR algorithm you look at will make tweaks to what I’ve described to meet their desired visual and performance quality. For example, Disney’s BRDF incorporates the metallic parameter when determining specular color, doesn’t have the Cook-Torrence denominator, and has a more complex diffuse model. The end goal of PBR is a unified shader model which pleases the art team!

This covers punctual light sources, in the next part of this series I’ll dive into how we can use similar concepts for environment mapped lighting. Then, in the final part, I’ll touch on how the BRDF is beginning to be extended for real-time into a BSDF (Bidirectional Scattering Distribution Function) where sub-surface scattering and refraction are also taken into account.

I didn’t want to clutter up this post with my own implementation, but if you’re interested in reading about what I did (with links to code) you can find it here: PBR Demystified Part 1 (My Implementation).