The Bidirectional Reflectance Distribution Function (BRDF) Look-up Table

Pre-calculating and storing part of the BRDF in a look-up table saves CPU usage during runtime

This document will not go too far into deep science-talk, as explaining the physics behind the "physically" part of "physically-based rendering" is out of its scope. Instead, this document is focused on how to do it rather than how it works. So, let's just say that the BRDF is a function that determines how light reflects off something, and it depends on the lighting model used. In this case, the lighting model is a Cook-Torrance microfacet specular model. The specifics of this model can be found in the Epic Games paper mentioned before.

However, as a stepping off point and to provide a few searchable terms, the method demonstrated in this example is based on a simplification called the "split-sum approximation". This approximation allows a significant part of the BRDF to become independent of both the model and the environment, so it can be extracted. The extracted component takes two inputs: the roughness of the object, and the cosine of the angle between the normal and the view vector () to produce two outputs: the scale and the bias to the value F0, with a range between 0 and 1. F0 is multiplied by the scale with the bias being added after.

Note: F0 measures the proportion of the incoming light that is reflected back as specular when the incident light is perpendicular to the surface. The output of the BRDF modifies this value based on the properties of the material.

This part of the BRDF can be trivially pre-calculated and stored in a 2D look-up texture (2D LUT) that can be used with any environment map or model. The two inputs will define the 2D coordinates of the point that should be sampled on the texture. The computation of this texture is done in the CPU and stored in 16-bit per component for proper precision with RG1616 texture format.

A utility function provided with the PowerVR Framework called pvr::utils::generateCookTorranceBRDFLUT(...) can be used to perform this calculation offline. It can be found in PVRUtils.cpp/PBRUtils.h.

Performing this calculation offline is a considerable optimisation as it would be very difficult to calculate the full BRDF during runtime and still obtain reasonable application performance. More information on similar optimisations can be found in Optimising the Shaders.

The image below shows the generated texture look-up table, with the red channel being the scale and green channel being the bias to F0:

Cook-Torrance Specular Look-up Table

Other BRDFs may affect how light reflects at grazing or head-on angles, or how reflective materials of different roughnesses appear at these angles. Additionally, other functions may have brighter and darker areas.