According to learnopengl.com PBR - or physically based rendering - is "...a collection of render techniques that are more or less based on the same underlying theory that more closely matches that of the physical world...[it] aims to mimic light in a physically plausible way...[and] generally looks more realistic compared to our original lighting algorithms like Phong an Blinn-Phong...PBR is still nonetheless an approximation of reality...which is why it's not called physical shading, but physically based shading. For a PBR lighting model to be considered physically based, it has to satisfy the following 3 conditions:
1. Be based on the microfacet surface model.
2. Be energy conserving.
3. Use a physically based BRDF."
The microfacet model is an approach to lighting that treats the surface of all things as if they were covered in microscopic mirrors. When these mirrors (or microfacets) all reflect in the same direction you get a highly reflective effect on the eye. When these mirrors reflect in many different directions you get a scuffed "rough" reflection. Thus every surface is treated as having a roughness/smoothness value or some variation thereof. From learnopengl.com:
2. Energy Conservation:
From learnopengl.com: "The microfacet approximation employs a form of energy conservation: outgoing light energy should never exceed the incoming light energy (excluding emissive surfaces). Looking at the above image we see the specular reflection area increase, but also its brightness decrease at increasing roughness levels. If the specular intensity were to be the same at each pixel (regardless of the size of the specular shape) the rougher surfaces would emit much more energy, violating the energy conservation principle...An additional subtlety when it comes to reflection and refraction are surfaces that are metallic. Metallic surfaces react different to light compared to non-metallic surfaces (also known as dielectrics). Metallic surfaces follow the same principles of reflection and refraction, but all refracted light gets directly absorbed without scattering. This means metallic surfaces only leave reflected or specular light; metallic surfaces show no diffuse colors."
"The BRDF, or bidirectional reflective distribution function, is a function that takes as input the incoming (light) direction ωi, the outgoing (view) direction ωo, the surface normal n, and a surface parameter a that represents the microsurface’s roughness. The BRDF approximates how much each individual light ray ωi contributes to the final reflected light of an opaque surface given its material properties. For instance, if the surface has a perfectly smooth surface ( like a mirror) the BRDF function would return 0.0 for all incoming light rays ωi except the one ray that has the same (reflected) angle as the outgoing ray ωo at which the function returns 1.0.
A BRDF approximates the material’s reflective and refractive properties based on the previously discussed microfacet theory. For a BRDF to be physically plausible it has to respect the law of energy conservation i.e. the sum of reflected light should never exceed the amount of incoming light. Technically, Blinn-Phong is considered a BRDF taking the same ωi and ωo as inputs. However, Blinn-Phong is not considered physically based as it doesn’t adhere to the energy conservation principle. There are several physically based BRDFs out there to approximate the surface’s reaction to light. However, almost all real-time PBR render pipelines use a BRDF known as the Cook-Torrance BRDF."
The learnopengl.com PBR shader uses a lookup texture to get the BRDF (brdflut). This is sometimes referred to as "fake BRDF." The brdf texture included with the two PBR shaders is considered to be "universal" and need not ever change from material to material. You can just leave it in the specular slot every time. From polycount.com:
As I've tried to do throughout, I've broken down some of these principles into simpler shaders so you can how they can be used on their own.
The learnopengl.com PBR shader uses multiple lights. So here I broke that down into a Blinn-Phong. You can adjust the number of lights you need and add the color and position of each in the shader:
Here is the "fake BRDF" technique. It's actually really simple but I find this very cool. All you do is create a fresnel (09_fresnel) and exchange the vector 2 texture coordinates of the given texture with it. Something like this:
vec4 iridescence = texture(texture4,vec2(ndotv,0));
You can readily see how it works and change these textures with anything you want, really:
The PBR shader splits the lighting in two ways: diffuse lighting, and specular. It further reduces the specular lighting into two parts: the BRDF, and the IBL specular map. The BRDF is shown above. Here is the second part of it. Note this and the PBR shaders are using something called "equirectangular" textures. There is no need to convert them to cubemaps. If you search for "HDRI's" you can find a lot of these for free on the webz:
The PBR shader uses heightmaps and I wasn't sure if there was one "official" method of getting height information so I made one with parallax and one with tessellation. That ought to cover everything. Parallax:
I included with the above and below shader only the bare essential textures. But you can search for PBR textures and there are a lot of them for free with "do whatever you want with this" kinds of licenses. I included a list of them near the bottom of this post. Here this is shown with a texture from the following collection:
I tried to follow the learnopengl.com PBR shader as closely as possible. Some of the ambient light was too dark. I wasn't getting good specular IBL. My roughness at 0 looked funky so I clamped it just slightly. Little tweaks like that. And you can adjust all of it. I'm not sure but I'm almost certain these PBR materials are meant to be Z-sorted. The article said nothing about it but the reason I believe this to be the case is because if they are not then any lights added to the shadowed side of the object look very dulled and the surface doesn't look right. You can see that for yourself.
There is a bit of an art to using the PBR shader. It's not always a magical production. For instance whether the ao texture is more white or more black will affect the outcome. Not all the PBR materials I downloaded came with ao maps or heightmaps. So you may have to improvise depending on this. The basics, however, are that white areas of the metallic texture will be metallic. Dark areas of the roughness texture will be highly reflective (that's a bit counter-intuitive). You can mess with the black and white textures I added, rearranging them to get different effects.
I added this small number at the end of this line to counter the strong black ambience (as seen in the above picture, which looks just a bit washed-out to me) but you can adjust it (line 201 in the tessellation PBR and line 211 in the parallax PBR):
Lo += (kD * albedo / PI + spec) * radiance * ndotl + 0.0075;
I also added a flashlight option. Just put the script on the object and drag the player into the slot. But it's rudimentary. I figured someone better at coding may be able to develop it if they want and my goal was to get a flashlight working with the z-sorted materials (what a bizarre little obsession with the flashlight I have).
Here is a list of free PBR sources:
PBR + equirectangular photos: