Last active
October 26, 2023 06:18
-
-
Save romainguy/a2e9208f14cae37c579448be99f78f25 to your computer and use it in GitHub Desktop.
D_GGX in mediump/half float
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// From https://github.com/google/filament | |
float D_GGX(float linearRoughness, float NoH, const vec3 h) { | |
// Walter et al. 2007, "Microfacet Models for Refraction through Rough Surfaces" | |
// In mediump, there are two problems computing 1.0 - NoH^2 | |
// 1) 1.0 - NoH^2 suffers floating point cancellation when NoH^2 is close to 1 (highlights) | |
// 2) NoH doesn't have enough precision around 1.0 | |
// Both problem can be fixed by computing 1-NoH^2 in highp and providing NoH in highp as well | |
// However, we can do better using Lagrange's identity: | |
// ||a x b||^2 = ||a||^2 ||b||^2 - (a . b)^2 | |
// since N and H are unit vectors: ||N x H||^2 = 1.0 - NoH^2 | |
// This computes 1.0 - NoH^2 directly (which is close to zero in the highlights and has | |
// enough precision). | |
// Overall this yields better performance, keeping all computations in mediump | |
#ifdef TARGET_MOBILE | |
vec3 NxH = cross(shading_normal, h); | |
float oneMinusNoHSquared = dot(NxH, NxH); | |
#else | |
float oneMinusNoHSquared = 1.0 - NoH * NoH; | |
#endif | |
float a = NoH * linearRoughness; | |
float k = linearRoughness / (oneMinusNoHSquared + a * a); | |
float d = k * k * (1.0 / PI); | |
return saturateMediump(d); | |
} |
@romainguy Just a note, in the followup comment with your definition of saturateMedium, you define MEDIUMP_FLT_MIN but use MEDIUMP_FLT_MAX :) Not that it's too hard to figure out what value the latter might have anyway of course.
Good catch :)
@romainguy , do you have any licensing terms for this? preferably a BSD license? Cheers.
Found this over in the UE4 codebase, no less, but properly cited!
Nice :) Our production version is here: https://github.com/google/filament/blob/master/shaders/src/brdf.fs#L54
@StAardvark To answer your question, the license is Apache 2.0 (see URL above)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
With:
#define MEDIUMP_FLT_MIN 0.00006103515625
#define MEDIUMP_FLT_MAX 65504.0
#ifdef TARGET_MOBILE
#define saturateMediump(x) min(x, MEDIUMP_FLT_MAX)
#else
#define saturateMediump(x) x
#endif