engine icon indicating copy to clipboard operation
engine copied to clipboard

[Question] Confused about the fresnel formula

Open scarletsky opened this issue 4 years ago • 3 comments

The origin fresnel schlick is:

This is what Filament do (From brdf.fs)

vec3 F_Schlick(const vec3 f0, float f90, float VoH) {
    // Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering"
    return f0 + (f90 - f0) * pow5(1.0 - VoH);
}

vec3 F_Schlick(const vec3 f0, float VoH) {
    float f = pow(1.0 - VoH, 5.0);
    return f + f0 * (1.0 - f);
}

float F_Schlick(float f0, float f90, float VoH) {
    return f0 + (f90 - f0) * pow5(1.0 - VoH);
}

This is what Babylon.js do (From pbrBRDFFunctions.fx)

vec3 fresnelSchlickGGX(float VdotH, vec3 reflectance0, vec3 reflectance90)
{
    return reflectance0 + (reflectance90 - reflectance0) * pow5(1.0 - VdotH);
}

float fresnelSchlickGGX(float VdotH, float reflectance0, float reflectance90)
{
    return reflectance0 + (reflectance90 - reflectance0) * pow5(1.0 - VdotH);
}

This is what Three.js do (From bsdfs.glsl.js)

vec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {
	// Original approximation by Christophe Schlick '94
	// float fresnel = pow( 1.0 - dotLH, 5.0 );
	// Optimized variant (presented by Epic at SIGGRAPH '13)
	// https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf
	float fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );
	return ( 1.0 - specularColor ) * fresnel + specularColor;
} // validated

This is what PlayCanvas do (From fresnelSchlick.frag)

void getFresnel() {
    float fresnel = 1.0 - max(dot(dNormalW, dViewDirW), 0.0);
    float fresnel2 = fresnel * fresnel;
    fresnel *= fresnel2 * fresnel2;
    fresnel *= dGlossiness * dGlossiness;
    dSpecularity = dSpecularity + (1.0 - dSpecularity) * fresnel;

    #ifdef CLEARCOAT
    // ...
    #endif
}

All of them use the half vector when calculating fresnel except playcanvas. The three.js implementation is a little different, and it is migrated from 2013SiggraphPresentationsNotes.

I have the following confusion:

  1. Why playcanvas use V dot N instead of V dot H ?
  2. What does dGlossiness * dGlossiness do here ? Is it used to replace f90 - f0 ?

scarletsky avatar Apr 22 '21 01:04 scarletsky

@scarletsky - great timing, @raytranuk is just investigating the lighting problems with this specifically ;)

mvaligursky avatar Apr 22 '21 07:04 mvaligursky

@scarletsky - you observations were correct - the fresnel implementation in PlayCanvas was not using the half-angle and this did result in non-standard specular lighting results that differed significantly from other implementations. A related PR has now been submitted: https://github.com/playcanvas/engine/pull/3172 - which switches the fresnel calculations to use the half-angle and should bring PlayCanvas more in line with other implementations. The use dGlossiness in the fresnel calculation is also non-standard in Cook-Torrance PBR models - but is used a bit like a Geometry term in the Blinn-Phong model that is the default for punctual lights in PlayCanvas.

raytranuk avatar May 25 '21 14:05 raytranuk

related to https://github.com/playcanvas/engine/issues/3013

mvaligursky avatar Jun 22 '22 11:06 mvaligursky

Hey @mvaligursky and @GSterbrant - I'm scanning some older issues to see if any can be closed. What's the current status of this one?

willeastcott avatar Oct 16 '22 00:10 willeastcott

This should have been fixed in #4386.

GSterbrant avatar Mar 16 '23 16:03 GSterbrant