This is a GGX distribution function taken from
[1]:
- {l Code}: {l Select All Code}
float DGgx( float NoH, float roughness ){
// Note: Generally sin2 + cos2 = 1
// Also: Dgtr = c / (a * cos2 + sin2)
// So...
float Krough2 = roughness * roughness;
float denom = 1.0 + NoH * NoH * ( Krough2 - 1.0 );
return Krough2 / ( PI * denom * denom );
}
Where
NoH is the dot product of the normal and
the light angle (argh no not if it's image-based) and
roughness is the value from the roughness texture, it returns...something. I understood the math a couple weeks ago before I switched to a 2D project and it's hard to return to this stuff. My point is that the metallic/roughness pipeline is standard, so when it comes to "glossy" and "tail" values you may not be going with current best practices. Generally the main parameters are metallic (the F0 from dielectric to mirror-like) and roughness (how rough the surface is).
[2]In most simple implementations, F0 (derived from the metallic texture) just interpolates from the fully-rough calculation to the fully-mirror-like calculation. In the case of image-based lighting, a pre-blur is usally applied to a copy of the environment map (though not in [2]; Trent likes to stay on the cutting edge). This is known as the split sum approximation; an approximation because the blur is omnidirectional and thus loses sharp grazing non-metallic specular reflections. So you have a couple of environment/cube maps for your shader to choose from depending on how diffuse light should be at any given point. The return value from the GGX function helps the shader determine exactly how diffuse the reflection should be at the fragment, from fully blurred to a perfect mirror.
As for what makes GGX different from Blinn-Phong and other older distribution functions, GGX just does more math and is better.