KhronosGroup / glTF-Sample-Viewer

Physically-Based Rendering in glTF 2.0 using WebGL
Apache License 2.0
1.28k stars 235 forks source link

Specular distribution function must be normalized/clamped for physically correct values #557

Open rsahlin opened 4 months ago

rsahlin commented 4 months ago

In order for the glTF sample viewer to be physically correct the specular normal distribution factor - D_GGX in the shader - must be clamped to [0.0- 1.0] This factor, which is a means to provide a 'made up' specular lobe in the absens of a light solid angle, is used together with the light intensity. It follows simple logic that any factor that is used in calculations together with light intensity must be within the 0 - 1 range. Otherwise light is magically removed or added.

In the sample-viewer, this means that the return value from the D_GGX function MUST be clamped in the [0.0 - 1.0] range.

The output can be checked to see if it follows the Fresnel power law for unpolarized light. This states that the reflectivity and transmission factor is calculated at the interface between the media using index of refraction, at normal incidence this is: Reflectivityfactor = (IOR1 - IOR2) / (IOR1 + IOR2) ^2 For the default glTF air to material interface this becomes: Reflectivityfactor = (1.5 - 1.0) / (1.5 + 1.0) ^2 = 0.04

This means that specular light makes up 0.04 of the incoming light at normal incidence and transmitted light makes up the remaining 0.96. 0.04 + 0.96 = 1.0

Attached is the fresnel test model and reference image. The test model has a 1 * 1 meter material facing the camera, the material is perfectly smooth with a basecolor of [0,0,0] just to isolate the specular factor. A directional light is placed so that light falls straight onto the surface, at normal incidence. Light intensity is 1000 meaning that the sampleviewer exposure setting must be set to 0.001

Below image is correct output - the reflectiv intensity shows up as sRGB [0.22,0.22,0.22] - converted to linear light this equals to [0.04,0.04, 0.04] which is the correct result

image fresneltest.zip

This is the output from sampleviewer - it clearly shows that the specular contribution is massively inflated - this is because the D_GGX function must be limited to 1.0

image

UX3D-haertl commented 2 months ago

We can definetly clamp the value anyways, but I can not reproduce the bright lobe in sample viewer. This is probably because of the other issue you mentioned about 0 roughness, but even with a small roughness value the light is not really visible for me (even with intensity 1). I tried some values and could not find any which showed a too bright light.