Browse Source

Merge pull request #7748 from Popov72/pbr-sheen

Added the roughness and albedoScaling parameters to PBR sheen
mergify[bot] 5 năm trước cách đây
mục cha
commit
36e33abb71

+ 4 - 0
dist/preview release/what's new.md

@@ -20,6 +20,10 @@
 
 - Ammo.js IDL exposed property update and raycast vehicle stablization support ([MackeyK24](https://github.com/MackeyK24))
 
+### Materials
+
+- Added the `roughness` and `albedoScaling` parameters to PBR sheen ([Popov72](https://github.com/Popov72))
+
 ## Bugs
 
 - Fix infinite loop in `GlowLayer.unReferenceMeshFromUsingItsOwnMaterial` ([Popov72](https://github.com/Popov72)

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

@@ -128,6 +128,14 @@ export class PBRMaterialPropertyGridComponent extends React.Component<IPBRMateri
             { label: "Alpha", value: 87 },
         ];
 
+        (material.sheen as any)._useRoughness = (material.sheen as any)._useRoughness ?? material.sheen.roughness !== null;
+        material.sheen.roughness = material.sheen.roughness ?? (material.sheen as any)._saveRoughness ?? 0;
+
+        if (!(material.sheen as any)._useRoughness) {
+            (material.sheen as any)._saveRoughness = material.sheen.roughness;
+            material.sheen.roughness = null;
+        }
+
         return (
             <div className="pane">
                 <CommonMaterialPropertyGridComponent globalState={this.props.globalState} lockObject={this.props.lockObject} material={material} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
@@ -208,6 +216,11 @@ export class PBRMaterialPropertyGridComponent extends React.Component<IPBRMateri
                             <SliderLineComponent label="Intensity" target={material.sheen} propertyName="intensity" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                             <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} />
+                            <CheckBoxLineComponent label="Use roughness" target={material.sheen} propertyName="_useRoughness" />
+                            { (material.sheen as any)._useRoughness &&
+                                <SliderLineComponent label="Roughness" target={material.sheen} propertyName="roughness" minimum={0} maximum={1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                            }
+                            <CheckBoxLineComponent label="Albedo scaling" target={material.sheen} propertyName="albedoScaling" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                         </div>
                     }
                 </LineContainerComponent>

+ 9 - 0
loaders/src/glTF/2.0/Extensions/KHR_materials_sheen.ts

@@ -13,6 +13,7 @@ interface IKHR_materials_sheen {
     intensityFactor: number;
     colorFactor: number[];
     colorIntensityTexture: ITextureInfo;
+    roughnessFactor: number;
 }
 
 /**
@@ -86,6 +87,14 @@ export class KHR_materials_sheen implements IGLTFLoaderExtension {
             }));
         }
 
+        if (properties.roughnessFactor !== undefined) {
+            babylonMaterial.sheen.roughness = properties.roughnessFactor;
+        } else {
+            babylonMaterial.sheen.roughness = 0;
+        }
+
+        babylonMaterial.sheen.albedoScaling = true;
+
         return Promise.all(promises).then(() => { });
     }
 }

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

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

+ 32 - 1
src/Materials/PBR/pbrSheenConfiguration.ts

@@ -17,6 +17,8 @@ export interface IMaterialSheenDefines {
     SHEEN_TEXTURE: boolean;
     SHEEN_TEXTUREDIRECTUV: number;
     SHEEN_LINKWITHALBEDO: boolean;
+    SHEEN_ROUGHNESS: boolean;
+    SHEEN_ALBEDOSCALING: boolean;
 
     /** @hidden */
     _areTexturesDirty: boolean;
@@ -65,6 +67,26 @@ export class PBRSheenConfiguration {
     @expandToProperty("_markAllSubMeshesAsTexturesDirty")
     public texture: Nullable<BaseTexture> = null;
 
+    private _roughness: Nullable<number> = null;
+    /**
+     * Defines the sheen roughness.
+     * It is not taken into account if linkSheenWithAlbedo is true.
+     * To stay backward compatible, material roughness is used instead if sheen roughness = null
+     */
+    @serialize()
+    @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+    public roughness: Nullable<number> = null;
+
+    private _albedoScaling = false;
+    /**
+     * If true, the sheen effect is layered above the base BRDF with the albedo-scaling technique.
+     * It allows the strength of the sheen effect to not depend on the base color of the material,
+     * making it easier to setup and tweak the effect
+     */
+    @serialize()
+    @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+    public albedoScaling = false;
+
     /** @hidden */
     private _internalMarkAllSubMeshesAsTexturesDirty: () => void;
 
@@ -110,6 +132,8 @@ export class PBRSheenConfiguration {
         if (this._isEnabled) {
             defines.SHEEN = this._isEnabled;
             defines.SHEEN_LINKWITHALBEDO = this._linkSheenWithAlbedo;
+            defines.SHEEN_ROUGHNESS = this._roughness !== null;
+            defines.SHEEN_ALBEDOSCALING = this._albedoScaling;
 
             if (defines._areTexturesDirty) {
                 if (scene.texturesEnabled) {
@@ -125,6 +149,8 @@ export class PBRSheenConfiguration {
             defines.SHEEN = false;
             defines.SHEEN_TEXTURE = false;
             defines.SHEEN_LINKWITHALBEDO = false;
+            defines.SHEEN_ROUGHNESS = false;
+            defines.SHEEN_ALBEDOSCALING = false;
         }
     }
 
@@ -147,6 +173,10 @@ export class PBRSheenConfiguration {
                 this.color.g,
                 this.color.b,
                 this.intensity);
+
+            if (this._roughness !== null) {
+                uniformBuffer.updateFloat("vSheenRoughness", this._roughness);
+            }
         }
 
         // Textures
@@ -229,7 +259,7 @@ export class PBRSheenConfiguration {
      * @param uniforms defines the current uniform list.
      */
     public static AddUniforms(uniforms: string[]): void {
-        uniforms.push("vSheenColor", "vSheenInfos", "sheenMatrix");
+        uniforms.push("vSheenColor", "vSheenRoughness", "vSheenInfos", "sheenMatrix");
     }
 
     /**
@@ -238,6 +268,7 @@ export class PBRSheenConfiguration {
      */
     public static PrepareUniformBuffer(uniformBuffer: UniformBuffer): void {
         uniformBuffer.addUniform("vSheenColor", 4);
+        uniformBuffer.addUniform("vSheenRoughness", 1);
         uniformBuffer.addUniform("vSheenInfos", 2);
         uniformBuffer.addUniform("sheenMatrix", 16);
     }

+ 6 - 0
src/Shaders/ShadersInclude/lightFragment.fx

@@ -76,6 +76,12 @@
                 #ifdef SHEEN_LINKWITHALBEDO
                     // BE Carefull: Sheen intensity is replacing the roughness value.
                     preInfo.roughness = sheenIntensity;
+                #else
+                    #ifdef HEMILIGHT{X}
+                        preInfo.roughness = sheenRoughness;
+                    #else
+                        preInfo.roughness = adjustRoughnessFromLightProperties(sheenRoughness, light{X}.vLightSpecular.a, preInfo.lightDistance);
+                    #endif
                 #endif
                 info.sheen = computeSheenLighting(preInfo, normalW, sheenColor, specularEnvironmentR90, AARoughnessFactors.x, light{X}.vLightDiffuse.rgb);
             #endif

+ 41 - 1
src/Shaders/ShadersInclude/pbrBRDFFunctions.fx

@@ -39,6 +39,18 @@
     }
 #endif
 
+/* NOT USED
+#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)
     {
@@ -48,7 +60,7 @@
     }
 #endif
 
-#if defined(SHEEN) && defined(REFLECTION)
+#if defined(SHEEN) && defined(ENVIRONMENTBRDF)
     /**
      * The sheen BRDF not containing F can be easily stored in the blue channel of the BRDF texture.
      * The blue channel contains DCharlie * VAshikhmin * NdotL as a lokkup table
@@ -136,6 +148,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 +258,33 @@ float normalDistributionFunction_TrowbridgeReitzGGX(float NdotH, float alphaG)
     {
         return 1. / (4. * (NdotL + NdotV - NdotL * NdotV));
     }
+
+    /* NOT USED
+    #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

+ 3 - 0
src/Shaders/ShadersInclude/pbrFragmentDeclaration.fx

@@ -100,6 +100,9 @@ uniform mat4 view;
 // Sheen
 #ifdef SHEEN
     uniform vec4 vSheenColor;
+    #ifdef SHEEN_ROUGHNESS
+        uniform float vSheenRoughness;
+    #endif
 
     #ifdef SHEEN_TEXTURE
         uniform vec2 vSheenInfos;

+ 1 - 0
src/Shaders/ShadersInclude/pbrUboDeclaration.fx

@@ -50,6 +50,7 @@ uniform Material
     uniform mat4 anisotropyMatrix;
 
     uniform vec4 vSheenColor;
+    uniform float vSheenRoughness;
     uniform vec2 vSheenInfos;
     uniform mat4 sheenMatrix;
 

+ 77 - 41
src/Shaders/pbr.fragment.fx

@@ -205,6 +205,7 @@ void main(void) {
         vec3 baseColor = surfaceAlbedo;
 
         #ifdef REFLECTANCE
+            // *** NOT USED ANYMORE ***
             // Following Frostbite Remapping,
             // https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf page 115
             // vec3 f0 = 0.16 * reflectance * reflectance * (1.0 - metallic) + baseColor * metallic;
@@ -551,10 +552,17 @@ void main(void) {
             #ifdef SHEEN_TEXTURE
                 sheenColor.rgb *= toLinearSpace(sheenMapData.rgb);
             #endif
-            float sheenRoughness = roughness;
+            
+            #ifdef SHEEN_ROUGHNESS
+                float sheenRoughness = vSheenRoughness;
+            #else
+                float sheenRoughness = roughness;
+            #endif
 
             // Sheen Lobe Layering.
-            sheenIntensity *= (1. - reflectance);
+            #if !defined(SHEEN_ALBEDOSCALING)
+                sheenIntensity *= (1. - reflectance);
+            #endif
 
             // Remap F0 and sheen.
             sheenColor *= sheenIntensity;
@@ -886,8 +894,17 @@ void main(void) {
     #endif
 
     // _____________________________ Sheen Environment Oclusion __________________________
-    #if defined(SHEEN) && defined(REFLECTION)
-        vec3 sheenEnvironmentReflectance = getSheenReflectanceFromBRDFLookup(sheenColor, environmentBrdf);
+    #if defined(SHEEN) && defined(ENVIRONMENTBRDF)
+        /*#ifdef SHEEN_SOFTER
+            vec3 environmentSheenBrdf = vec3(0., 0., getBRDFLookupCharlieSheen(NdotV, sheenRoughness));
+        #else*/
+            #ifdef SHEEN_ROUGHNESS
+                vec3 environmentSheenBrdf = getBRDFLookup(NdotV, sheenRoughness);
+            #else
+                vec3 environmentSheenBrdf = environmentBrdf;
+            #endif
+        /*#endif*/
+        vec3 sheenEnvironmentReflectance = getSheenReflectanceFromBRDFLookup(sheenColor, environmentSheenBrdf);
 
         #ifdef RADIANCEOCCLUSION
             sheenEnvironmentReflectance *= seo;
@@ -900,6 +917,13 @@ 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 sheenAlbedoScaling = 1.0 - sheenIntensity * max(max(sheenColor.r, sheenColor.g), sheenColor.b) * environmentSheenBrdf.b;
+        #endif
     #endif
 
     // _________________________ Clear Coat Environment Oclusion __________________________
@@ -935,10 +959,10 @@ void main(void) {
 
             #ifdef REFLECTION
                 environmentIrradiance *= absorption;
+            #endif
 
-                #ifdef SHEEN
-                    sheenEnvironmentReflectance *= absorption;
-                #endif
+            #if defined(SHEEN) && defined(ENVIRONMENTBRDF)
+                sheenEnvironmentReflectance *= absorption;
             #endif
 
             specularEnvironmentReflectance *= absorption;
@@ -952,10 +976,10 @@ void main(void) {
 
         #ifdef REFLECTION
             environmentIrradiance *= conservationFactor;
+        #endif
 
-            #ifdef SHEEN
-                sheenEnvironmentReflectance *= conservationFactor;
-            #endif
+        #if defined(SHEEN) && defined(ENVIRONMENTBRDF)
+            sheenEnvironmentReflectance *= conservationFactor;
         #endif
 
         specularEnvironmentReflectance *= conservationFactor;
@@ -1040,6 +1064,10 @@ void main(void) {
         #endif
     #endif
 
+    #if defined(SHEEN) && defined(SHEEN_ALBEDOSCALING) && defined(ENVIRONMENTBRDF)
+        surfaceAlbedo.rgb = sheenAlbedoScaling * surfaceAlbedo.rgb;
+    #endif
+
     // _____________________________ Irradiance ______________________________________
     #ifdef REFLECTION
         vec3 finalIrradiance = environmentIrradiance;
@@ -1059,6 +1087,10 @@ void main(void) {
         #if defined(ENVIRONMENTBRDF) && defined(MS_BRDF_ENERGY_CONSERVATION)
             finalSpecularScaled *= energyConservationFactor;
         #endif
+
+        #if defined(SHEEN) && defined(ENVIRONMENTBRDF) && defined(SHEEN_ALBEDOSCALING)
+            finalSpecularScaled *= sheenAlbedoScaling;
+        #endif
     #endif
 
     // _____________________________ Radiance ________________________________________
@@ -1071,6 +1103,10 @@ void main(void) {
         #if defined(ENVIRONMENTBRDF) && defined(MS_BRDF_ENERGY_CONSERVATION)
             finalRadianceScaled *= energyConservationFactor;
         #endif
+
+        #if defined(SHEEN) && defined(ENVIRONMENTBRDF) && defined(SHEEN_ALBEDOSCALING)
+            finalRadianceScaled *= sheenAlbedoScaling;
+        #endif
     #endif
 
     // _____________________________ Refraction ______________________________________
@@ -1079,6 +1115,27 @@ void main(void) {
         finalRefraction *= refractionTransmittance;
     #endif
 
+    // ________________________________ Sheen ________________________________________
+    #ifdef SHEEN
+        vec3 finalSheen = sheenBase * sheenColor;
+        finalSheen = max(finalSheen, 0.0);
+
+        vec3 finalSheenScaled = finalSheen * vLightingIntensity.x * vLightingIntensity.w;
+        // #if defined(ENVIRONMENTBRDF) && defined(MS_BRDF_ENERGY_CONSERVATION)
+            // The sheen does not use the same BRDF so not energy conservation is possible
+            // Should be less a problem as it is usually not metallic
+            // finalSheenScaled *= energyConservationFactor;
+        // #endif
+        
+        #if defined(REFLECTION) && defined(ENVIRONMENTBRDF)
+            vec3 finalSheenRadiance = environmentSheenRadiance.rgb;
+            finalSheenRadiance *= sheenEnvironmentReflectance;
+
+            // Full value needed for alpha. 
+            vec3 finalSheenRadianceScaled = finalSheenRadiance * vLightingIntensity.z;
+        #endif
+    #endif
+
     // _____________________________ Clear Coat _______________________________________
     #ifdef CLEARCOAT
         vec3 finalClearCoat = clearCoatBase;
@@ -1107,27 +1164,6 @@ void main(void) {
         #endif
     #endif
 
-    // ________________________________ Sheen ________________________________________
-    #ifdef SHEEN
-        vec3 finalSheen = sheenBase * sheenColor;
-        finalSheen = max(finalSheen, 0.0);
-
-        vec3 finalSheenScaled = finalSheen * vLightingIntensity.x * vLightingIntensity.w;
-        // #if defined(ENVIRONMENTBRDF) && defined(MS_BRDF_ENERGY_CONSERVATION)
-            // The sheen does not use the same BRDF so not energy conservation is possible
-            // Should be less a problem as it is usually not metallic
-            // finalSheenScaled *= energyConservationFactor;
-        // #endif
-        
-        #ifdef REFLECTION
-            vec3 finalSheenRadiance = environmentSheenRadiance.rgb;
-            finalSheenRadiance *= sheenEnvironmentReflectance;
-
-            // Full value needed for alpha. 
-            vec3 finalSheenRadianceScaled = finalSheenRadiance * vLightingIntensity.z;
-        #endif
-    #endif
-
     // _____________________________ Highlights on Alpha _____________________________
     #ifdef ALPHABLEND
         float luminanceOverAlpha = 0.0;
@@ -1192,30 +1228,30 @@ void main(void) {
     //	finalSpecular			* vLightingIntensity.x * vLightingIntensity.w +
         finalSpecularScaled +
     #endif
-    #ifdef CLEARCOAT
-    // Computed in the previous step to help with alpha luminance.
-    //	finalClearCoat			* vLightingIntensity.x * vLightingIntensity.w +
-        finalClearCoatScaled +
-    #endif
     #ifdef SHEEN
     // Computed in the previous step to help with alpha luminance.
     //	finalSheen  			* vLightingIntensity.x * vLightingIntensity.w +
         finalSheenScaled +
     #endif
+    #ifdef CLEARCOAT
+    // Computed in the previous step to help with alpha luminance.
+    //	finalClearCoat			* vLightingIntensity.x * vLightingIntensity.w +
+        finalClearCoatScaled +
+    #endif
     #ifdef REFLECTION
     // Comupted in the previous step to help with alpha luminance.
     //	finalRadiance			* vLightingIntensity.z +
         finalRadianceScaled +
+        #if defined(SHEEN) && defined(ENVIRONMENTBRDF)
+        //  Comupted in the previous step to help with alpha luminance.
+        //  finalSheenRadiance * vLightingIntensity.z 
+            finalSheenRadianceScaled +
+        #endif
         #ifdef CLEARCOAT
         //  Comupted in the previous step to help with alpha luminance.
         //  finalClearCoatRadiance * vLightingIntensity.z 
             finalClearCoatRadianceScaled +
         #endif
-        #ifdef SHEEN
-        //  Comupted in the previous step to help with alpha luminance.
-        //  finalSheenRadiance * vLightingIntensity.z 
-            finalSheenRadianceScaled +
-        #endif
     #endif
     #ifdef SS_REFRACTION
         finalRefraction			* vLightingIntensity.z +