For this entry into our this is Sparta series we are going to talk about our shading system. It’s going to be quite a bit in depth so be prepared. After this we will go back to talking a bit more about the softer parts of the game. As mentioned in the last post we are careful to do our calculations in a physically correct color space. But when we come to our shading equations we take it one step further by using a physically based BRDF(basically a shading equation) instead of one based on observation (like the phong lighting equation). For people interested in a deeper understanding than we can cover here you can either look at my Nordic Game Conference Speak on the subject or you can read Naty Hoffman’s excellent papers from siggraph 2010 Here and Here.
So what do we mean with physically based ? What we mean is that we respect the basic properties of light, for example when light hit’s a surface a pprart of it is reflected (this is what we call specular light, light that has never entered the material and therefore isn’t colored by it) another part of the light enters the surface and some of this is absorbed by the surface but some re-exits the surface this is the part we call diffuse light and is the part of light that takes on the color of the object, so this is the light we mostly see. Well one thing that a physically based lighting (PBL from now on) should ensure is that the amount of light that bounces from the object can’t be greater than the amount of light hitting it. Pretty obvious but not a rule in computer graphics in fact fixing so that this is true is called energy conversation and is an important part of being physically based, Neither Phong or Blinn-Phong are energy conserving in fact booth of them reflect more light than hits them under a lot of material presets.
For Blinn-phong or Phong this can be fixed by adding a normalization factor that guarantees that the amount of light reflected cannot be bigger than the incoming light.The normalization factors does this by lowering the strength of the specular light if the area reflecting light is larger and making the light stronger if the area is smaller so that the same amount of light is reflected no matter the size of the highlight assuming the surface’s substance is the same.
This all works using something called a Micro-Facet BRDF(Bi-Directional Reflectance Distribution Function). While this might sound advanced it is basically creating the surface as a multitude of facets of perfectly reflecting mirrors.The rougher the surface of the material the more different directions the mirrors point in. And the BRDF calculates which % of mirrors are pointing directly at your eye. This is what is referred to as the roughness of the material and is what decided if we have a large weak specular or a small strong.
The other value that is necessary when doing a physically based solution is a substance value, this is the reflective property of the surface which means how much light it reflects and is based on it’s real material. For example all steel has the same substance because it’s steel but some steel has a mirror like reflection and some does not and this is due to the roughness. Brushed steel has a very high roughness for example.
Of course just having energy conservation inside the specular isn’t enough what if we have a nice shiny white material then it would reflect a lot of light but a lot of light would enter and re-exit the surface meaning it still emits more light than hit it. In this case we need energy conversation between the specular and the diffuse part. This is due to the fact that light that bounced can’t enter the surface because it has already bounced, this sounds obvious but a lot of game engines doesn’t handle this properly.
However the big advantage for me with going physically based (except that the Artists saves a ton of time thanks to much easier maps to work with) is that because your values actually mean something you can use them to handle ambient light and reflections with proper blurriness too. So that reflections and specular works together. This requires that you blurs your cubemaps correctly but works like a charm and is used in engines like CryEngine3.
For our cubemaps we however went one step further. Normal cubemaps has the problem that they don’t match up with the objects reflecting in them they are just a image being reflected. We instead use a technique called Box projected cubemaps where we project the cube images on a mesh representing the room and then correctly fins the reflection intersection with that one and finds the proper pixel. This allows us to have working reflections booth glossy and non glossy essentially for free. The same technique is also used to re project bounced light inside the room on objects moving through it.
In these examples you can see the effect of the box projection in the first one I have modified the wall segments closer to me to have a blurry reflection so you can se the button in the middle of the room of them (You can also observe the visual difference compared to the last one that doesn’t feel as metallic even where we can se no reflection this is an effect of our energy-conservation between specular and diffuse light.
Backing all this is a fully deferred renderer, but thanks to our use of a physically based shading model we can produce a wealth of different materials without letting our G-Buffer get out of control size wise. We hope you have enjoyed this look into the more technical side of Project Temporality and as always don’t hesitate to tell us what kind of information you are interested in hearing about.
Edited. I don't know why it lost all it's formatting but it's fixed now.