Browse Source

Sheen: add albedo scaling and softer look (uses V_charlie instead of V_Ashikhmin)

Popov72 5 years ago
parent
commit
6cef84adb3

+ 2 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/materials/pbrMaterialPropertyGridComponent.tsx

@@ -209,6 +209,8 @@ export class PBRMaterialPropertyGridComponent extends React.Component<IPBRMateri
                             <Color3LineComponent label="Color" target={material.sheen} propertyName="color" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                             <TextureLinkLineComponent label="Texture" texture={material.sheen.texture} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} />
                             <SliderLineComponent label="Roughness" target={material.sheen} propertyName="roughness" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                            <CheckBoxLineComponent label="Softer look" target={material.sheen} propertyName="softer" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                            <CheckBoxLineComponent label="Albedo scaling" target={material.sheen} propertyName="albedoScaling" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                         </div>
                     }
                 </LineContainerComponent>

+ 2 - 0
src/Materials/PBR/pbrBaseMaterial.ts

@@ -215,6 +215,8 @@ export class PBRMaterialDefines extends MaterialDefines
     public SHEEN_TEXTUREDIRECTUV = 0;
     public SHEEN_LINKWITHALBEDO = false;
     public SHEEN_ROUGHNESS = false;
+    public SHEEN_SOFTER = false;
+    public SHEEN_ALBEDOSCALING = false;
 
     public SUBSURFACE = false;
 

+ 16 - 0
src/Materials/PBR/pbrSheenConfiguration.ts

@@ -18,6 +18,8 @@ export interface IMaterialSheenDefines {
     SHEEN_TEXTUREDIRECTUV: number;
     SHEEN_LINKWITHALBEDO: boolean;
     SHEEN_ROUGHNESS: boolean;
+    SHEEN_SOFTER: boolean;
+    SHEEN_ALBEDOSCALING: boolean;
 
     /** @hidden */
     _areTexturesDirty: boolean;
@@ -76,6 +78,16 @@ export class PBRSheenConfiguration {
     @expandToProperty("_markAllSubMeshesAsTexturesDirty")
     public roughness = 0.0;
 
+    private _softer = false;
+    @serialize()
+    @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+    public softer = false;
+
+    private _albedoScaling = false;
+    @serialize()
+    @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+    public albedoScaling = false;
+
     /** @hidden */
     private _internalMarkAllSubMeshesAsTexturesDirty: () => void;
 
@@ -122,6 +134,8 @@ export class PBRSheenConfiguration {
             defines.SHEEN = this._isEnabled;
             defines.SHEEN_LINKWITHALBEDO = this._linkSheenWithAlbedo;
             defines.SHEEN_ROUGHNESS = this._roughness !== 0;
+            defines.SHEEN_SOFTER = this._softer;
+            defines.SHEEN_ALBEDOSCALING = this._albedoScaling;
 
             if (defines._areTexturesDirty) {
                 if (scene.texturesEnabled) {
@@ -138,6 +152,8 @@ export class PBRSheenConfiguration {
             defines.SHEEN_TEXTURE = false;
             defines.SHEEN_LINKWITHALBEDO = false;
             defines.SHEEN_ROUGHNESS = false;
+            defines.SHEEN_SOFTER = false;
+            defines.SHEEN_ALBEDOSCALING = false;
         }
     }
 

+ 36 - 0
src/Shaders/ShadersInclude/pbrBRDFFunctions.fx

@@ -39,6 +39,16 @@
     }
 #endif
 
+#if defined(SHEEN) && defined(SHEEN_SOFTER)
+// Approximation of (integral on hemisphere)[f_sheen*cos(theta)*dtheta*dphi]
+float getBRDFLookupCharlieSheen(float NdotV, float perceptualRoughness)
+{
+    float c = 1.0 - NdotV;
+    float c3 = c*c*c;
+    return 0.65584461 * c3 + 1.0 / (4.16526551 + exp(-7.97291361*perceptualRoughness+6.33516894));
+}
+#endif
+
 #if !defined(ENVIRONMENTBRDF) || defined(REFLECTIONMAP_SKYBOX) || defined(ALPHAFRESNEL)
     vec3 getReflectanceFromAnalyticalBRDFLookup_Jones(float VdotN, vec3 reflectance0, vec3 reflectance90, float smoothness)
     {
@@ -136,6 +146,7 @@ float normalDistributionFunction_TrowbridgeReitzGGX(float NdotH, float alphaG)
 }
 
 #ifdef SHEEN
+    // http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf
     // https://knarkowicz.wordpress.com/2018/01/04/cloth-shading/
     float normalDistributionFunction_CharlieSheen(float NdotH, float alphaG)
     {
@@ -245,6 +256,31 @@ float normalDistributionFunction_TrowbridgeReitzGGX(float NdotH, float alphaG)
     {
         return 1. / (4. * (NdotL + NdotV - NdotL * NdotV));
     }
+
+    #ifdef SHEEN_SOFTER
+        // http://www.aconty.com/pdf/s2017_pbs_imageworks_sheen.pdf
+        float l(float x, float alphaG)
+        {
+            float oneMinusAlphaSq = (1.0 - alphaG) * (1.0 - alphaG);
+            float a = mix(21.5473, 25.3245, oneMinusAlphaSq);
+            float b = mix(3.82987, 3.32435, oneMinusAlphaSq);
+            float c = mix(0.19823, 0.16801, oneMinusAlphaSq);
+            float d = mix(-1.97760, -1.27393, oneMinusAlphaSq);
+            float e = mix(-4.32054, -4.85967, oneMinusAlphaSq);
+            return a / (1.0 + b * pow(x, c)) + d * x + e;
+        }
+
+        float lambdaSheen(float cosTheta, float alphaG)
+        {
+            return abs(cosTheta) < 0.5 ? exp(l(cosTheta, alphaG)) : exp(2.0 * l(0.5, alphaG) - l(1.0 - cosTheta, alphaG));
+        }
+
+        float visibility_CharlieSheen(float NdotL, float NdotV, float alphaG)
+        {
+            float G = 1.0 / (1.0 + lambdaSheen(NdotV, alphaG) + lambdaSheen(NdotL, alphaG));
+            return G / (4.0 * NdotV * NdotL);
+        }
+    #endif
 #endif
 
 // ______________________________________________________________________

+ 6 - 2
src/Shaders/ShadersInclude/pbrDirectLightingFunctions.fx

@@ -143,9 +143,13 @@ vec3 computeProjectionTextureDiffuseLighting(sampler2D projectionLightSampler, m
         // vec3 fresnel = fresnelSchlickGGX(info.VdotH, reflectance0, reflectance90);
         float fresnel = 1.;
         float distribution = normalDistributionFunction_CharlieSheen(NdotH, alphaG);
-        float ashikhminvisibility = visibility_Ashikhmin(info.NdotL, info.NdotV);
+        #ifdef SHEEN_SOFTER
+            float visibility = visibility_CharlieSheen(info.NdotL, info.NdotV, alphaG);
+        #else
+            float visibility = visibility_Ashikhmin(info.NdotL, info.NdotV);
+        #endif
 
-        float sheenTerm = fresnel * distribution * ashikhminvisibility;
+        float sheenTerm = fresnel * distribution * visibility;
         return sheenTerm * info.attenuation * info.NdotL * lightColor;
     }
 #endif

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

@@ -560,7 +560,9 @@ void main(void) {
             #endif
 
             // Sheen Lobe Layering.
-            sheenIntensity *= (1. - reflectance);
+            #if !defined(SHEEN_ALBEDOSCALING)
+                sheenIntensity *= (1. - reflectance);
+            #endif
 
             // Remap F0 and sheen.
             sheenColor *= sheenIntensity;
@@ -893,10 +895,14 @@ void main(void) {
 
     // _____________________________ Sheen Environment Oclusion __________________________
     #if defined(SHEEN) && defined(REFLECTION)
-        #ifdef SHEEN_ROUGHNESS
-            vec3 environmentSheenBrdf = getBRDFLookup(NdotV, sheenRoughness);
+        #ifdef SHEEN_SOFTER
+            vec3 environmentSheenBrdf = vec3(0., 0., getBRDFLookupCharlieSheen(NdotV, sheenRoughness));
         #else
-            vec3 environmentSheenBrdf = environmentBrdf;
+            #ifdef SHEEN_ROUGHNESS
+                vec3 environmentSheenBrdf = getBRDFLookup(NdotV, sheenRoughness);
+            #else
+                vec3 environmentSheenBrdf = environmentBrdf;
+            #endif
         #endif
         vec3 sheenEnvironmentReflectance = getSheenReflectanceFromBRDFLookup(sheenColor, environmentSheenBrdf);
 
@@ -911,6 +917,21 @@ void main(void) {
                 #endif
             #endif
         #endif
+
+        #if defined(SHEEN_ALBEDOSCALING)
+            // Sheen Lobe Layering.
+            // environmentSheenBrdf.b is (integral on hemisphere)[f_sheen*cos(theta)*dtheta*dphi], which happens to also be the directional albedo needed for albedo scaling.
+            // See section 6.2.3 in https://dassaultsystemes-technology.github.io/EnterprisePBRShadingModel/spec-2021x.md.html#components/sheen
+            float albedoScaling = 1.0 - sheenIntensity * max(max(sheenColor.r, sheenColor.g), sheenColor.b) * environmentSheenBrdf.b;
+            #ifdef REFLECTION
+                environmentIrradiance *= albedoScaling;
+                specularEnvironmentReflectance *= albedoScaling;
+            #endif
+            #ifdef SPECULARTERM
+                specularBase *= albedoScaling;
+            #endif
+            diffuseBase *= albedoScaling;
+        #endif
     #endif
 
     // _________________________ Clear Coat Environment Oclusion __________________________