Developer’s point of view – Basics

In previous post, I explained what you had to know about Physically Based Rendering if you were an artist. If you’re a developer, and reading this article, you may have tried, or are planning to implement your own PBR system. If you started to read some of the available literature, you’ve probably been struck by the math complexity of it, and by the lack of explanation of the big picture. You usually see articles that focus on specifics parts of the process, and don’t talk much about other parts as they are assumed easier. At some point you have to assemble all these parts, and I had a hard time figuring out how to do it in my readings. I guess it’s considered basic stuff for other authors, but I think it deserves its proper explanation.

I don’t pretend these articles will enlighten you to the point you are ready to implement your own system, but I hope they will give you solid basis and understanding to start reading the literature without saying “WTF?? on every line as I did.

You can find a lexical, at the end, with all the strange words you’ll come across and their explanations.

So here is what I figured out about using PBR and lighting in general in a 3D rendering pipeline.

# Ligthing

So first, lets talk about lighting in games. It all boils down to 2 things :

- Computing
**Diffuse**reflection: This represent the light that reflects off a surface in all directions - Computing
**Specular**reflection : This represent the light that reflects off a surface directly to your eye.

This image from wikipedia is the most simple and yet the most helpful to understand this

To compute each of these factors, we’re going to use a function. This function answers to the delicate name of**Bidirectional Reflectance Distribution Function or BRDF**.

Don’t be scared by this, it’s a big name for just a function really. Usually, it will be a shader function.

Of course there are different BRDFs depending on what you want to compute, and on the lighting model you use. The BRDFs are usually called by the name of the guys that discovered/elaborated them.

Also, most of the time, in implementations for real time rendering, those BRDFs are approximated for the sake of performance. And incidentally, those approximations also have names, that can be people names or technique names…

# Lighting in PBR

Computing lighting for PBR is exactly the same as with the current rendering ( the system we use today with ambient, diffuse, specular, sometimes called ad-hoc system in the literature) :

For each light source, compute the diffuse factor and the specular factor. The main difference is that the BRDFs used are different, more physically accurate, and works predictably under different light sources with few parameter entries.

*So what is a light source?*

**Direct light source**

*Something that emits light*. In games the most common light sources are Directional lights (think of the sun), Spot lights (think of a torch light), Point lights (think of a light bulb).

That’s what is commonly used in the ad-hoc system, and PBR also handle those types of lights.

** **

**Indirect light source**

*Something that reflects light and indirectly lights its surroundings. *Think for example of a red wall next to a car at daytime, the sunlight hits the wall and the wall reflects red light that, in turn, lights up the car.

This is not handled by the ad-hoc system, or very poorly faked with ambient lighting.

This part is optional for PBR, but that’s actually the part you really want. because that’s what make things pretty!

In games, indirect lighting is done by using an environment map as a light source. This technique is called** Image Based Lighting (IBL)**.

** **

So let’s say we’re looking for the full package. we need to compute diffuse and specular contribution for each light source be it direct or indirect.

To do so we need a BRDF for diffuse and a BRDF for specular, and stick to them for each light source for consistency. Also those BRDF should accept as entry the parameters we want to expose for the artists (base color, metalness, roughness), or derived parameters with minimal transformation.

So the pseudo code for a complete lighting is this :

1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
//direct lighting for each directLightSource { directDiffuseFactor = DiffuseBRDF(directlightSource) directSpecularFactor = SpecularBRDF(directLightSource) directLighting += Albedo * directDiffuseFactor + SpecColor * directSpecularFactor } //Indirect Lighting, done through Image Based Rendering with an environment map indirectDiffuseFactor = DiffuseBRDF(EnvMap) indirectSpecularFactor = SpecularBRDF(EnvMap) indirectLighting = Albedo * indirectDiffuseFactor + SpecColor * indirectSpecularFactor Lighting = directLighting + indirectLighting |

I’ll go into more details, in the posts serie, on how to compute each factors, but that’s pretty much it.

# Choosing your BRDFs

There is a vast choice of BRDF, and I’m not going to talk about all of them but focus on the ones that I use in my implementation. I’ll just guide you to alternatives and provide links to relevant articles for more details.** **

I chose to use the same BRDF as the ones used in Unreal Engine 4 from this article by Brian Karis, as I completely trust his judgement. The provided code helped a great deal, but it was far from straight forward to integrate. In the end I had to fully research, and understand all the whereabouts of BRDFs.

** **

*Diffuse BRDF : ***Lambert**

*Diffuse BRDF :*

The most used diffuse BRDF in games. It’s very popular because it’s very cheap to compute and gives good results. This is the most simple way of computing diffuse. here are the details

** ***Some Alternatives :*

**Oren-Nayar : **Gives better visual results than classic Lambert, and has the advantage of using an entry parameter called roughness…rings a bell? Unfortunately, the additional computation cost is not really worth it,IMO. Details here** **

**Harahan-Krueger :** Takes into consideration sub-surface scattering for diffuse lighting (every material surface has layers and light scatters into those different layers before going out of the material in a random direction). A lot of computations compared to Lambert, but may be important if you want to have a good sub surface scattering look for skin for example. more details in this paper

**Specular BRDF : Cook-Torrance**

This is a bit more complicated for specular. We need a physically plausible BRDF. We use what is called a **Microfacet BRDF**. So what is it?

It states that at a micro level a surface is not plane, but formed of a multitude of little randomly aligned surfaces, the microfacets. Those surfaces acts as small mirrors that reflects incoming light. The idea behind this BRDF is that only some of those facets may be oriented so that the incoming light reflects to your eye. The smoother the surface, the more all facets are aligned, and the most neat is the light reflection. In the contrary, if a surface is rough, the facets are more randomly oriented so the light reflection is scattered on the surface, and the reflection looks more blurry.

** **The microfacet BRDF we use is called

**Cook-Torrance.**From my readings, I couldn’t find any implementation that use another specular BRDF. It seems like this is the global form of any microfacet BRDF.

1 |
f = D * F * G / (4 * (N.L) * (N.V)); |

**N.L** is the dot product between the normal of the shaded surface and the light direction.

**N.V** is the dot product between the normal of the shaded surface and the view direction.

The other terms are :

**Normal Distribution Function called D**(for distribution). You may also find some references to it as NDF. It computes the distribution of the microfacets for the shaded surface**Fresnel factor called F**. Discovered by Augustin Fresnel (frenchies are sooo clever), it describes how light reflects and refracts at the intersection of two different media (most often in computer graphics : Air and the shaded surface)**Geometry shadowing term G**. Defines the shadowing from the microfacets

That’s where it gets complicated. For each of these terms, there are several models or approximations to computed them.

I’ve settled to use those models and approximations :

**D :****Trowbridge-Reitz/****GGX**normal Distribution function.**F : Fresnel term Schlick**’s approximation**G : Schlick-GGX**approximation

I won’t go into the details of all the alternatives I just want to expose an overview of the whole process first. But I’ll dive into more technical details on the terms I use, in following posts. To have a neat overview of all alternatives you can see this post on Brian Karis’s blog.

** **** **

That sums up the whole process, but there is still much to explain. In next post I’ll make a focus on indirect lighting, as it’s the part that gave me the hardest time to wrap my head around. I’ll explain the Image Based Lighting technique used, and how you can compute diffuse and specular from an Environment Map.

**Lexical : **

**Diffuse reflection :** light that reflects from a surface in every direction.

**Specular reflection :** light that reflects from a surface toward the viewer.

**Bidirectional Reflectance Distribution Function or BRDF :** a function to compute Diffuse or Specular reflection.

**Image Based Rendering or IBL : **a technique that uses an image as a light source

**Microfacet Specular BRDF : **A specular BRDF that assumes a surface is made of a multitude of very small randomly aligned surfaces: the microfacets. it depends on 3 factors called D, F and G.

**Normal Distribution Function called D **(for distribution). You may also find some references to it as NDF. It computes the distribution of the microfacets for the shaded surface

**Fresnel factor called F**. Discovered by Augustin Fresnel (frenchies are sooo clever), it describes how light reflects and refracts at the intersection of two different media (most often in computer graphics : Air and the shaded surface)

**Geometry shadowing term G**. Defines the shadowing from the micro facets