Jelajahi Sumber

Sync PBR sheen with the latest spec

Popov72 4 tahun lalu
induk
melakukan
d84f97c990

+ 2 - 1
dist/preview release/glTF2Interface/babylon.glTF2Interface.d.ts

@@ -1028,8 +1028,9 @@ declare module BABYLON.GLTF2 {
     /** @hidden */
     interface IKHRMaterialsSheen {
         sheenColorFactor?: number[];
-        sheenTexture?: ITextureInfo;
+        sheenColorTexture?: ITextureInfo;
         sheenRoughnessFactor?: number;
+        sheenRoughnessTexture?: ITextureInfo;
     }
 
     /**

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

@@ -226,10 +226,12 @@ 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} isLinear={true} />
                             <TextureLinkLineComponent label="Sheen" texture={material.sheen.texture} onTextureCreated={(texture) => material.sheen.texture = texture} onTextureRemoved={() => material.sheen.texture = null} material={material} onSelectionChangedObservable={this.props.onSelectionChangedObservable} onDebugSelectionChangeObservable={this._onDebugSelectionChangeObservable} />
+                            <TextureLinkLineComponent label="Roughness" texture={material.sheen.textureRoughness} onTextureCreated={(texture) => material.sheen.textureRoughness = texture} onTextureRemoved={() => material.sheen.textureRoughness = null} 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="Use roughness from main texture" target={material.sheen} propertyName="useRoughnessFromMainTexture" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                             <CheckBoxLineComponent label="Albedo scaling" target={material.sheen} propertyName="albedoScaling" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
                         </div>
                     }

+ 10 - 2
loaders/src/glTF/2.0/Extensions/KHR_materials_sheen.ts

@@ -71,8 +71,8 @@ export class KHR_materials_sheen implements IGLTFLoaderExtension {
             babylonMaterial.sheen.color = Color3.Black();
         }
 
-        if (properties.sheenTexture) {
-            promises.push(this._loader.loadTextureInfoAsync(`${context}/sheenTexture`, properties.sheenTexture, (texture) => {
+        if (properties.sheenColorTexture) {
+            promises.push(this._loader.loadTextureInfoAsync(`${context}/sheenColorTexture`, properties.sheenColorTexture, (texture) => {
                 texture.name = `${babylonMaterial.name} (Sheen Color)`;
                 babylonMaterial.sheen.texture = texture;
             }));
@@ -84,7 +84,15 @@ export class KHR_materials_sheen implements IGLTFLoaderExtension {
             babylonMaterial.sheen.roughness = 0;
         }
 
+        if (properties.sheenRoughnessTexture) {
+            promises.push(this._loader.loadTextureInfoAsync(`${context}/sheenRoughnessTexture`, properties.sheenRoughnessTexture, (texture) => {
+                texture.name = `${babylonMaterial.name} (Sheen Roughness)`;
+                babylonMaterial.sheen.textureRoughness = texture;
+            }));
+        }
+
         babylonMaterial.sheen.albedoScaling = true;
+        babylonMaterial.sheen.useRoughnessFromMainTexture = false;
 
         return Promise.all(promises).then(() => { });
     }

+ 15 - 1
serializers/src/glTF/2.0/Extensions/KHR_materials_sheen.ts

@@ -93,7 +93,21 @@ export class KHR_materials_sheen implements IGLTFExporterExtensionV2 {
                     let textureIndex = this._getTextureIndex(babylonMaterial.sheen.texture);
 
                     if (textureIndex > -1) {
-                        sheenInfo.sheenTexture = this._textureInfos[textureIndex] ;
+                        sheenInfo.sheenColorTexture = this._textureInfos[textureIndex];
+                    }
+                }
+
+                if (babylonMaterial.sheen.textureRoughness && !babylonMaterial.sheen.useRoughnessFromMainTexture) {
+                    let textureIndex = this._getTextureIndex(babylonMaterial.sheen.textureRoughness);
+
+                    if (textureIndex > -1) {
+                        sheenInfo.sheenRoughnessTexture = this._textureInfos[textureIndex];
+                    }
+                } else if (babylonMaterial.sheen.texture && babylonMaterial.sheen.useRoughnessFromMainTexture) {
+                    let textureIndex = this._getTextureIndex(babylonMaterial.sheen.texture);
+
+                    if (textureIndex > -1) {
+                        sheenInfo.sheenRoughnessTexture = this._textureInfos[textureIndex];
                     }
                 }
 

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

@@ -238,10 +238,13 @@ export class PBRMaterialDefines extends MaterialDefines
 
     public SHEEN = false;
     public SHEEN_TEXTURE = false;
+    public SHEEN_TEXTURE_ROUGHNESS = false;
     public SHEEN_TEXTUREDIRECTUV = 0;
     public SHEEN_LINKWITHALBEDO = false;
     public SHEEN_ROUGHNESS = false;
     public SHEEN_ALBEDOSCALING = false;
+    public SHEEN_USE_ROUGHNESS_FROM_TEXTURE = false;
+    public SHEEN_TEXTURE_ROUGHNESS_IDENTICAL = false;
 
     public SUBSURFACE = false;
 

+ 65 - 8
src/Materials/PBR/pbrSheenConfiguration.ts

@@ -15,10 +15,13 @@ import { EffectFallbacks } from '../effectFallbacks';
 export interface IMaterialSheenDefines {
     SHEEN: boolean;
     SHEEN_TEXTURE: boolean;
+    SHEEN_TEXTURE_ROUGHNESS: boolean;
     SHEEN_TEXTUREDIRECTUV: number;
     SHEEN_LINKWITHALBEDO: boolean;
     SHEEN_ROUGHNESS: boolean;
     SHEEN_ALBEDOSCALING: boolean;
+    SHEEN_USE_ROUGHNESS_FROM_TEXTURE: boolean;
+    SHEEN_TEXTURE_ROUGHNESS_IDENTICAL: boolean;
 
     /** @hidden */
     _areTexturesDirty: boolean;
@@ -61,12 +64,22 @@ export class PBRSheenConfiguration {
     /**
      * Stores the sheen tint values in a texture.
      * rgb is tint
-     * a is a intensity or roughness if roughness has been defined
+     * a is a intensity or roughness if the roughness property has been defined and useRoughnessFromTexture is true (in that case, textureRoughness won't be used)
+     * If the roughness property has been defined and useRoughnessFromTexture is false then the alpha channel is not used to modulate roughness
      */
     @serializeAsTexture()
     @expandToProperty("_markAllSubMeshesAsTexturesDirty")
     public texture: Nullable<BaseTexture> = null;
 
+    private _useRoughnessFromMainTexture = true;
+    /**
+     * Indicates that the alpha channel of the texture property will be used for roughness.
+     * Has no effect if the roughness (and texture!) property is not defined
+     */
+    @serialize()
+    @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+    public useRoughnessFromMainTexture = true;
+
     private _roughness: Nullable<number> = null;
     /**
      * Defines the sheen roughness.
@@ -77,6 +90,15 @@ export class PBRSheenConfiguration {
     @expandToProperty("_markAllSubMeshesAsTexturesDirty")
     public roughness: Nullable<number> = null;
 
+    private _textureRoughness: Nullable<BaseTexture> = null;
+    /**
+     * Stores the sheen roughness in a texture.
+     * alpha channel is the roughness. This texture won't be used if the texture property is not empty and useRoughnessFromTexture is true
+     */
+    @serializeAsTexture()
+    @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+    public textureRoughness: Nullable<BaseTexture> = null;
+
     private _albedoScaling = false;
     /**
      * If true, the sheen effect is layered above the base BRDF with the albedo-scaling technique.
@@ -117,6 +139,12 @@ export class PBRSheenConfiguration {
                         return false;
                     }
                 }
+
+                if (this._textureRoughness && MaterialFlags.SheenTextureEnabled) {
+                    if (!this._textureRoughness.isReadyOrNotBlocking()) {
+                        return false;
+                    }
+                }
             }
         }
 
@@ -134,6 +162,8 @@ export class PBRSheenConfiguration {
             defines.SHEEN_LINKWITHALBEDO = this._linkSheenWithAlbedo;
             defines.SHEEN_ROUGHNESS = this._roughness !== null;
             defines.SHEEN_ALBEDOSCALING = this._albedoScaling;
+            defines.SHEEN_USE_ROUGHNESS_FROM_TEXTURE = this._useRoughnessFromMainTexture;
+            defines.SHEEN_TEXTURE_ROUGHNESS_IDENTICAL = this.texture !== null && this.texture._texture === this.textureRoughness?._texture;
 
             if (defines._areTexturesDirty) {
                 if (scene.texturesEnabled) {
@@ -142,6 +172,12 @@ export class PBRSheenConfiguration {
                     } else {
                         defines.SHEEN_TEXTURE = false;
                     }
+
+                    if (this._textureRoughness && MaterialFlags.SheenTextureEnabled) {
+                        MaterialHelper.PrepareDefinesForMergedUV(this._textureRoughness, defines, "SHEEN_TEXTURE_ROUGHNESS");
+                    } else {
+                        defines.SHEEN_TEXTURE_ROUGHNESS = false;
+                    }
                 }
             }
         }
@@ -151,6 +187,8 @@ export class PBRSheenConfiguration {
             defines.SHEEN_LINKWITHALBEDO = false;
             defines.SHEEN_ROUGHNESS = false;
             defines.SHEEN_ALBEDOSCALING = false;
+            defines.SHEEN_USE_ROUGHNESS_FROM_TEXTURE = false;
+            defines.SHEEN_TEXTURE_ROUGHNESS_IDENTICAL = false;
         }
     }
 
@@ -162,9 +200,13 @@ export class PBRSheenConfiguration {
      */
     public bindForSubMesh(uniformBuffer: UniformBuffer, scene: Scene, isFrozen: boolean): void {
         if (!uniformBuffer.useUbo || !isFrozen || !uniformBuffer.isSync) {
-            if (this._texture && MaterialFlags.SheenTextureEnabled) {
-                uniformBuffer.updateFloat2("vSheenInfos", this._texture.coordinatesIndex, this._texture.level);
-                MaterialHelper.BindTextureMatrix(this._texture, uniformBuffer, "sheen");
+            if ((this._texture || this._textureRoughness) && MaterialFlags.SheenTextureEnabled) {
+                uniformBuffer.updateFloat4("vSheenInfos", this._texture?.coordinatesIndex ?? this._textureRoughness?.coordinatesIndex ?? 0, this._texture?.level ?? 0, 0 /* not used */, this._textureRoughness?.level ?? 0);
+                if (this._texture) {
+                    MaterialHelper.BindTextureMatrix(this._texture, uniformBuffer, "sheen");
+                } else if (this._textureRoughness) {
+                    MaterialHelper.BindTextureMatrix(this._textureRoughness, uniformBuffer, "sheen");
+                }
             }
 
             // Sheen
@@ -184,6 +226,9 @@ export class PBRSheenConfiguration {
             if (this._texture && MaterialFlags.SheenTextureEnabled) {
                 uniformBuffer.setTexture("sheenSampler", this._texture);
             }
+            if (this.textureRoughness && (this.texture === null || this.texture._texture !== this.textureRoughness._texture) && MaterialFlags.SheenTextureEnabled) {
+                uniformBuffer.setTexture("sheenRoughnessSampler", this._textureRoughness);
+            }
         }
     }
 
@@ -197,6 +242,10 @@ export class PBRSheenConfiguration {
             return true;
         }
 
+        if (this._textureRoughness === texture) {
+            return true;
+        }
+
         return false;
     }
 
@@ -208,6 +257,10 @@ export class PBRSheenConfiguration {
         if (this._texture) {
             activeTextures.push(this._texture);
         }
+
+        if (this._textureRoughness) {
+            activeTextures.push(this._textureRoughness);
+        }
     }
 
     /**
@@ -218,6 +271,10 @@ export class PBRSheenConfiguration {
         if (this._texture && this._texture.animations && this._texture.animations.length > 0) {
             animatables.push(this._texture);
         }
+
+        if (this._textureRoughness && this._textureRoughness.animations && this._textureRoughness.animations.length > 0) {
+            animatables.push(this._textureRoughness);
+        }
     }
 
     /**
@@ -226,9 +283,8 @@ export class PBRSheenConfiguration {
      */
     public dispose(forceDisposeTextures?: boolean): void {
         if (forceDisposeTextures) {
-            if (this._texture) {
-                this._texture.dispose();
-            }
+            this._texture?.dispose();
+            this._textureRoughness?.dispose();
         }
     }
 
@@ -269,7 +325,7 @@ export class PBRSheenConfiguration {
     public static PrepareUniformBuffer(uniformBuffer: UniformBuffer): void {
         uniformBuffer.addUniform("vSheenColor", 4);
         uniformBuffer.addUniform("vSheenRoughness", 1);
-        uniformBuffer.addUniform("vSheenInfos", 2);
+        uniformBuffer.addUniform("vSheenInfos", 4);
         uniformBuffer.addUniform("sheenMatrix", 16);
     }
 
@@ -279,6 +335,7 @@ export class PBRSheenConfiguration {
      */
     public static AddSamplers(samplers: string[]): void {
         samplers.push("sheenSampler");
+        samplers.push("sheenRoughnessSampler");
     }
 
     /**

+ 10 - 1
src/Shaders/ShadersInclude/pbrBlockSheen.fx

@@ -25,6 +25,9 @@
         const in vec4 vSheenColor,
     #ifdef SHEEN_ROUGHNESS
         const in float vSheenRoughness,
+        #if defined(SHEEN_TEXTURE_ROUGHNESS) && !defined(SHEEN_TEXTURE_ROUGHNESS_IDENTICAL)
+            const in vec4 sheenMapRoughnessData,
+        #endif
     #endif
         const in float roughness,
     #ifdef SHEEN_TEXTURE
@@ -97,8 +100,14 @@
             
             #ifdef SHEEN_ROUGHNESS
                 float sheenRoughness = vSheenRoughness;
-                #ifdef SHEEN_TEXTURE
+                #if defined(SHEEN_TEXTURE) && defined(SHEEN_USE_ROUGHNESS_FROM_TEXTURE)
                     sheenRoughness *= sheenMapData.a;
+                #elif defined(SHEEN_TEXTURE_ROUGHNESS)
+                    #ifdef SHEEN_TEXTURE_ROUGHNESS_IDENTICAL
+                        sheenRoughness *= sheenMapData.a;
+                    #else
+                        sheenRoughness *= sheenMapRoughnessData.a;
+                    #endif
                 #endif
             #else
                 float sheenRoughness = roughness;

+ 1 - 1
src/Shaders/ShadersInclude/pbrFragmentDeclaration.fx

@@ -109,7 +109,7 @@ uniform mat4 view;
     #endif
 
     #ifdef SHEEN_TEXTURE
-        uniform vec2 vSheenInfos;
+        uniform vec4 vSheenInfos;
         uniform mat4 sheenMatrix;
     #endif
 #endif

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

@@ -131,6 +131,9 @@
             varying vec2 vSheenUV;
         #endif
         uniform sampler2D sheenSampler;
+        #if defined(SHEEN_ROUGHNESS) && defined(SHEEN_TEXTURE_ROUGHNESS) && !defined(SHEEN_TEXTURE_ROUGHNESS_IDENTICAL)
+            uniform sampler2D sheenRoughnessSampler;
+        #endif
     #endif
 #endif
 

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

@@ -56,7 +56,7 @@ uniform Material
 
     uniform vec4 vSheenColor;
     uniform float vSheenRoughness;
-    uniform vec2 vSheenInfos;
+    uniform vec4 vSheenInfos;
     uniform mat4 sheenMatrix;
 
     uniform vec3 vRefractionMicrosurfaceInfos;

+ 1 - 1
src/Shaders/ShadersInclude/pbrVertexDeclaration.fx

@@ -85,7 +85,7 @@ uniform float pointSize;
 // Sheen
 #ifdef SHEEN
     #ifdef SHEEN_TEXTURE
-        uniform vec2 vSheenInfos;
+        uniform vec4 vSheenInfos;
         uniform mat4 sheenMatrix;
     #endif
 #endif

+ 6 - 0
src/Shaders/pbr.fragment.fx

@@ -286,11 +286,17 @@ void main(void) {
         #ifdef SHEEN_TEXTURE
             vec4 sheenMapData = toLinearSpace(texture2D(sheenSampler, vSheenUV + uvOffset)) * vSheenInfos.y;
         #endif
+        #if defined(SHEEN_ROUGHNESS) && defined(SHEEN_TEXTURE_ROUGHNESS) && !defined(SHEEN_TEXTURE_ROUGHNESS_IDENTICAL)
+            vec4 sheenMapRoughnessData = texture2D(sheenRoughnessSampler, vSheenUV + uvOffset) * vSheenInfos.w;
+        #endif
 
         sheenBlock(
             vSheenColor,
         #ifdef SHEEN_ROUGHNESS
             vSheenRoughness,
+            #if defined(SHEEN_TEXTURE_ROUGHNESS) && !defined(SHEEN_TEXTURE_ROUGHNESS_IDENTICAL)
+                sheenMapRoughnessData,
+            #endif
         #endif
             roughness,
         #ifdef SHEEN_TEXTURE