Wednesday, 17 February 2016

Physically Based Rendering in Leadwerks (C++)

As part of my final year university work I’ve been looking into Physically Based Rendering(PBR) and its implementation. PBR is a method of generating images that takes physical values into account, this means lighting behaves much more predictably and accurately.

This link gives a fantastic, and in depth look into how PBR works in Remember Me. Notably, PBR systems aren’t all the same, often times they use different algorithms to generate images, and there are many ways to generate reflections for them.

This PBR uses a runtime rendered cubemap to generate reflections and ambient diffuse lighting on objects, nice for avoiding the flat lighting in shadowed areas problem. It then uses a physically based BRDF to generate specular highlights.Currently static models and animated models have shaders, there is also preliminary decal support. All light types are supported with shadowing. The materials use metalness/roughness maps.
There are a number of example assets in the zip file.

You’ll need the C++ version of Leadwerks for this one, the reflection generation code is written in C++ and relies on a number of OpenGL calls to function properly. This does mean however that you can generate a new reflection map at any point.

I was aiming for a similar system to what was used in GTAV. For that game a low poly, diffuse only environment map is generated each frame in order to render reflections. However for my work the performance isn’t quite high enough to generate a reflection map per frame yet. Reflections are generated as cube maps, that map is then sampled with GL_SEAMLESS_CUBEMAPPING enabled, the lowest mipmap is used for diffuse lighting then higher mip values are used for the specular reflections.

(If you are using the lua version of leadwerks, you may be able to use pre-blurred cube-maps and get acceptable results)

Here’s an example of the shaders working on a complex PBR asset. Built by Andrew Maximov,



I’m looking for feedback on how robust the system is, so here is a download link, you're free to use this as you please.

I’ve had to use the alpha channel for gloss values so transparency is a bit borked. Decals suffer from the alpha problem as well.
I’ve looked into binding reflection textures to the lighting shaders which would avoid the alpha hijacking. But it doesn’t seem to work if any post processing or water is used. If anyone can point me in the right direction here it would be appreciated.

This implementation uses normalised Blinn-Phong for the distribution term, Schlick’s approximation for Fresnel, and Smith’s shadowing function for the geometry term.

there was weird overlapping going on but putting an image here seemed to fix it... so here's my avatar! will fix this soon.