Parcourir la source

Merge pull request #1191 from sebavan/FixReflectanceFresnel

Fix white reflectance fresnel on specular.
David Catuhe il y a 9 ans
Parent
commit
040fb69e2a

+ 2 - 2
src/Shaders/ShadersInclude/pbrFunctions.fx

@@ -86,14 +86,14 @@ vec3 FresnelSchlickEnvironmentGGX(float VdotN, vec3 reflectance0, vec3 reflectan
 }
 
 // Cook Torance Specular computation.
-vec3 computeSpecularTerm(float NdotH, float NdotL, float NdotV, float VdotH, float roughness, vec3 specularColor)
+vec3 computeSpecularTerm(float NdotH, float NdotL, float NdotV, float VdotH, float roughness, vec3 specularColor, vec3 reflectance90)
 {
     float alphaG = convertRoughnessToAverageSlope(roughness);
     float distribution = normalDistributionFunction_TrowbridgeReitzGGX(NdotH, alphaG);
     float visibility = smithVisibilityG_TrowbridgeReitzGGX_Walter(NdotL, NdotV, alphaG);
     visibility /= (4.0 * NdotL * NdotV); // Cook Torance Denominator  integated in viibility to avoid issues when visibility function changes.
 
-    vec3 fresnel = fresnelSchlickGGX(VdotH, specularColor, vec3(1., 1., 1.));
+    vec3 fresnel = fresnelSchlickGGX(VdotH, specularColor, reflectance90);
 
     float specTerm = max(0., visibility * distribution) * NdotL;
     return fresnel * specTerm * kPi; // TODO: audit pi constants

+ 6 - 6
src/Shaders/ShadersInclude/pbrLightFunctions.fx

@@ -48,7 +48,7 @@ float computeDirectionalLightFalloff(vec3 lightDirection, vec3 directionToLightC
     return falloff;
 }
 
-lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, float rangeRadius, float roughness, float NdotV, out float NdotL) {
+lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, float rangeRadius, float roughness, float NdotV, vec3 reflectance90, out float NdotL) {
     lightingInfo result;
 
     vec3 lightDirection;
@@ -87,14 +87,14 @@ lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData,
         // Specular
         float NdotH = max(0.00000000001, dot(vNormal, H));
 
-        vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, specularColor);
+        vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, specularColor, reflectance90);
         result.specular = specTerm * attenuation;
     #endif
 
     return result;
 }
 
-lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec4 lightDirection, vec3 diffuseColor, vec3 specularColor, float rangeRadius, float roughness, float NdotV, out float NdotL) {
+lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec4 lightDirection, vec3 diffuseColor, vec3 specularColor, float rangeRadius, float roughness, float NdotV, vec3 reflectance90, out float NdotL) {
     lightingInfo result;
 
     vec3 lightOffset = lightData.xyz - vPositionW;
@@ -124,14 +124,14 @@ lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightDa
         // Specular
         float NdotH = max(0.00000000001, dot(vNormal, H));
 
-        vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, specularColor);
+        vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, specularColor, reflectance90);
         result.specular = specTerm  * attenuation;
     #endif
 
     return result;
 }
 
-lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, vec3 groundColor, float roughness, float NdotV, out float NdotL) {
+lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, vec3 groundColor, float roughness, float NdotV, vec3 reflectance90, out float NdotL) {
     lightingInfo result;
 
     // Roughness
@@ -149,7 +149,7 @@ lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4
         NdotL = max(0.00000000001, NdotL);
         float VdotH = clamp(0.00000000001, 1.0, dot(viewDirectionW, H));
 
-        vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, specularColor);
+        vec3 specTerm = computeSpecularTerm(NdotH, NdotL, NdotV, VdotH, roughness, specularColor, reflectance90);
         result.specular = specTerm;
     #endif
 

+ 3 - 3
src/Shaders/ShadersInclude/pbrLightFunctionsCall.fx

@@ -3,13 +3,13 @@
         vec3 vLightSpecular{X} = vec3(0.0);
     #endif
     #ifdef SPOTLIGHT{X}
-        info = computeSpotLighting(viewDirectionW, normalW, vLightData{X}, vLightDirection{X}, vLightDiffuse{X}.rgb, vLightSpecular{X}, vLightDiffuse{X}.a, roughness, NdotV, NdotL);
+        info = computeSpotLighting(viewDirectionW, normalW, vLightData{X}, vLightDirection{X}, vLightDiffuse{X}.rgb, vLightSpecular{X}, vLightDiffuse{X}.a, roughness, NdotV, specularEnvironmentR90, NdotL);
     #endif
     #ifdef HEMILIGHT{X}
-        info = computeHemisphericLighting(viewDirectionW, normalW, vLightData{X}, vLightDiffuse{X}.rgb, vLightSpecular{X}, vLightGround{X}, roughness, NdotV, NdotL);
+        info = computeHemisphericLighting(viewDirectionW, normalW, vLightData{X}, vLightDiffuse{X}.rgb, vLightSpecular{X}, vLightGround{X}, roughness, NdotV, specularEnvironmentR90, NdotL);
     #endif
     #if defined(POINTLIGHT{X}) || defined(DIRLIGHT{X})
-        info = computeLighting(viewDirectionW, normalW, vLightData{X}, vLightDiffuse{X}.rgb, vLightSpecular{X}, vLightDiffuse{X}.a, roughness, NdotV, NdotL);
+        info = computeLighting(viewDirectionW, normalW, vLightData{X}, vLightDiffuse{X}.rgb, vLightSpecular{X}, vLightDiffuse{X}.a, roughness, NdotV, specularEnvironmentR90, NdotL);
     #endif
     
     #ifdef SHADOW{X}

+ 10 - 4
src/Shaders/pbr.fragment.fx

@@ -293,6 +293,15 @@ void main(void) {
 	float NdotL = -1.;
 	lightingInfo info;
 
+	// Compute reflectance.
+	float reflectance = max(max(surfaceReflectivityColor.r, surfaceReflectivityColor.g), surfaceReflectivityColor.b);
+
+	// For typical incident reflectance range (between 4% to 100%) set the grazing reflectance to 100% for typical fresnel effect.
+    // For very low reflectance range on highly diffuse objects (below 4%), incrementally reduce grazing reflecance to 0%.
+    float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0);
+	vec3 specularEnvironmentR0 = surfaceReflectivityColor.rgb;
+	vec3 specularEnvironmentR90 = vec3(1.0, 1.0, 1.0) * reflectance90;
+
 #include<pbrLightFunctionsCall>[0..maxSimultaneousLights]
 
 #ifdef SPECULARTERM
@@ -466,9 +475,7 @@ void main(void) {
 	environmentRadiance *= vLightingIntensity.z;
 	environmentIrradiance *= vLightingIntensity.z;
 
-	// Compute reflection specular fresnel
-	vec3 specularEnvironmentR0 = surfaceReflectivityColor.rgb;
-	vec3 specularEnvironmentR90 = vec3(1.0, 1.0, 1.0);
+	// Specular Environment Fresnel.
 	vec3 specularEnvironmentReflectance = FresnelSchlickEnvironmentGGX(clamp(NdotV, 0., 1.), specularEnvironmentR0, specularEnvironmentR90, sqrt(microSurface));
 
 	// Compute refractance
@@ -510,7 +517,6 @@ void main(void) {
 #endif
 
 	// Apply Energy Conservation taking in account the environment level only if the environment is present.
-	float reflectance = max(max(surfaceReflectivityColor.r, surfaceReflectivityColor.g), surfaceReflectivityColor.b);
 	surfaceAlbedo.rgb = (1. - reflectance) * surfaceAlbedo.rgb;
 
 	refractance *= vLightingIntensity.z;