Skip to content

Instantly share code, notes, and snippets.

@romainguy
Last active October 26, 2023 06:18
Show Gist options
  • Star 22 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save romainguy/a2e9208f14cae37c579448be99f78f25 to your computer and use it in GitHub Desktop.
Save romainguy/a2e9208f14cae37c579448be99f78f25 to your computer and use it in GitHub Desktop.
D_GGX in mediump/half float
// 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
Copy link
Author

romainguy commented Sep 5, 2017

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

@hrydgard
Copy link

hrydgard commented Sep 5, 2017

@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.

@romainguy
Copy link
Author

romainguy commented Sep 5, 2017

Good catch :)

@StAardvark
Copy link

@romainguy , do you have any licensing terms for this? preferably a BSD license? Cheers.

@Kleptine
Copy link

Kleptine commented Jun 4, 2019

Found this over in the UE4 codebase, no less, but properly cited!

@romainguy
Copy link
Author

romainguy commented Jun 4, 2019

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