Sample scene with different PBR materials. |

This time we will talk about something really interesting and useful -

*Physically Based Rendering*. Actually, I am not going to explain everything about this topic, as it is huge and probably there is a ton of information that already exists on the web. However, I'd like to share my experience with adding*PBR*to my engine and struggles that I ran into during the process.
But what is

*PBR*? If you only know that it makes things fancy and realistic in the application, I will briefly give you an explanation. By this time you should realize that one of the main goals in computer graphics is to simulate "proper" light behavior. Somehow we want our objects in the scene to interact with light sources like in the real world. We want to shade them, have reflections and do many other complicated things. And it so happened that*J.Kajiya*introduced a general rendering equation in 1986:
And since then people have been trying to mimic and solve it for all kinds of purposes. Of course, games became 3D much later, but they also needed lights. People have also found partial solutions and approximations of that equation for real-time applications (i.e

*Lambert diffuse)*, but they were not 100% accurate. Just look at that nasty__indefinite__integral over the hemisphere above! How the heck we should compute it in real-time? This task seems to be impossible...
But approximations... They are everywhere in this world... Developers and researchers did not stop on

So as you can see we have diffuse and specular components. We can separate this integral in two integrals and solve them separately. Of course, for

Why? Well, we are calculating radiance for

Moving next, we should deal with a

The mip-map generation process required some additional code for my engine so I could load my

And that is it! I will leave my final

TOREAD:

*Lambert*and other simplified shading models, so that's why in the early 2000s*, PBR*shading model was introduced. In a way, it is another solution to that equation which takes some physical properties into consideration:*conservation of energy, microsurface scattering*and etc. So it is more "physical" and thus more accurate and computationally complicated. And fortunately, it was popularized for the real-time applications by companies like*Epic Games.*If you are not familiar with the concepts of*radiance, irradiance, flux, BRDF*you can read about them here. By the way, I have used the*Cook-Torrance BRDF*model, as it is very popular in rendering engines. (Read about it here)That's how our BRDF radiance equation looks now. D, F, G terms are explained in the link above. |

So as you can see we have diffuse and specular components. We can separate this integral in two integrals and solve them separately. Of course, for

*direct*lighting (from direct sources) it is not a big of a deal: we just compute a*Lambert diffuse*term for the left integral and*specular*term with all tricky but straightforward formulas:*D*for*GGX Distribution*,*F - Shlick-Fresnel*and*G*for*Smith's Geometry.*( So if things are already unclear, make sure to read the theory! ) In general, this is just some Maths that can be calculated in our shader. However, the results are not satisfying :(Why? Well, we are calculating radiance for

*direct lighting.*But look at our integral again. It's about*all*directions (*w*) over the hemisphere. Pretty unrealistic to compute, I agree... But it doesn't mean that we do not want to try! Let's dive into a more complicated part of*PBR*implementation -*IBL*or*Image Based Lighting.**Probably you have already realized that we would work with*

*environment maps / cubemaps.*That's a nice and relatively cheap way to calculate environment diffuse light. It is called an*irradiance map*. Basically, it is a pre-convoluted cubemap - for every direction over the hemisphere we take a sample in the cubemap. Fortunately, you can generate an*irradiance map*with a third-party tool, such as*CubeMapGen*by*AMD*, or you can precompute it by yourself in the code.Moving next, we should deal with a

*specular*part. It consists of 2 textures:*radiance*and*integration*maps. The second one is just a lookup texture for computing the BRDF, so you can download it from the Internet. However, the first one must consist of several pre-filtered mip-maps. Your shader will calculate an*indirect specular*with something like*split-sum approximation.*That's why for different roughness values on your material you would use different mip-maps of your cubemap. The screenshot below should give you an intuition.Image taken from https://polycount.com/discussion/139342/introducing-lys-open-beta |

The mip-map generation process required some additional code for my engine so I could load my

*irradiance map*into a*PBR*shader with all mips at once. For example, here is my*IBLRadianceMap*class:And that is it! I will leave my final

*PBR*shader/effect for you to explore. I understand that there may be many improvements, but for now, I am really satisfied with the results. As a result, I can load fancy 4K textures and get the realism out of them:)*Links:**1) https://learnopengl.com/PBR/Theory**2) https://blog.selfshadow.com/publications/s2013-shading-course/*TOREAD:

*"Physically Based Rendering: From Theory to Implementation"*by G.Humphreys and M. Pharr