While reading Physically Based Rendering in Filament I found a few interesting paragraphs in section 4.4.1 about optimizing the implementation of a GGX NDF approximation for half precision float
s. I understood that the calculation of 1 - dot(n, h) * dot(n,h)
can cause so called catastrophic cancellation and why using the cross product solves the problem, however I didn't get how is any of this related to half precision float
s.
It seems that GLSL does not have any half
specifier, unlike HLSL (which simply maps it to float
since D3D10 most likely because modern desktop hardware doesn't support it anyway; though it seems that with the newest hardware its back again). The thing with Filament is that it is primarly developed for mobile platforms like Android, where half precision float
s are supported in hardware.
I understand that using half precision float
s is important for performance on both mobile and the most modern desktop targets. As such I would like to understand how is the following code optimized for half precision float
s as I can see no half
specifier or similar, but merely some constant and a macro:
#define MEDIUMP_FLT_MAX 65504.0
#define saturateMediump(x) min(x, MEDIUMP_FLT_MAX)
float D_GGX(float roughness, float NoH, const vec3 n, const vec3 h) {
vec3 NxH = cross(n, h);
float a = NoH * roughness;
float k = roughness / (dot(NxH, NxH) + a * a);
float d = k * k * (1.0 / PI);
return saturateMediump(d);
}
For completeness, here is the unoptimized code:
float D_GGX(float NoH, float roughness) {
float a = NoH * roughness;
float k = roughness / (1.0 - NoH * NoH + a * a);
return k * k * (1.0 / PI);
}