Jelajahi Sumber

Merge pull request #8257 from Popov72/fix-nme-pbr

Fix nme pbr following latest changes for reflectance
sebavan 5 tahun lalu
induk
melakukan
b88a99f417

+ 47 - 6
src/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.ts

@@ -29,6 +29,7 @@ import { ClearCoatBlock } from './clearCoatBlock';
 import { SubSurfaceBlock } from './subSurfaceBlock';
 import { RefractionBlock } from './refractionBlock';
 import { PerturbNormalBlock } from '../Fragment/perturbNormalBlock';
+import { Constants } from '../../../../Engines/constants';
 
 const mapOutputToVariable: { [name: string] : [string, string] } = {
     "ambient":      ["finalAmbient", ""],
@@ -195,6 +196,22 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
     public enableSpecularAntiAliasing: boolean = false;
 
     /**
+     * Enables realtime filtering on the texture.
+     */
+    @editableInPropertyPage("Realtime filtering", PropertyTypeForEdition.Boolean, "RENDERING", { "notifiers": { "update": true }})
+    public realTimeFiltering: boolean = false;
+
+    /**
+     * Quality switch for realtime filtering
+     */
+    @editableInPropertyPage("Realtime filtering quality", PropertyTypeForEdition.List, "RENDERING", { "notifiers": { "update": true }, "options": [
+        { label: "Low", value: Constants.TEXTURE_FILTERING_QUALITY_LOW },
+        { label: "Medium", value: Constants.TEXTURE_FILTERING_QUALITY_MEDIUM },
+        { label: "High", value: Constants.TEXTURE_FILTERING_QUALITY_HIGH },
+    ]})
+    public realTimeFilteringQuality = Constants.TEXTURE_FILTERING_QUALITY_LOW;
+
+    /**
      * Defines if the material uses energy conservation.
      */
     @editableInPropertyPage("Energy Conservation", PropertyTypeForEdition.Boolean, "ADVANCED", { "notifiers": { "update": true }})
@@ -606,6 +623,12 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         defines.setValue("RADIANCEOVERALPHA", this.useRadianceOverAlpha, true);
         defines.setValue("SPECULAROVERALPHA", this.useSpecularOverAlpha, true);
         defines.setValue("SPECULARAA", this._scene.getEngine().getCaps().standardDerivatives && this.enableSpecularAntiAliasing, true);
+        defines.setValue("REALTIME_FILTERING", this.realTimeFiltering, true);
+        defines.setValue("NUM_SAMPLES", "" + this.realTimeFilteringQuality, true);
+
+        if (this._scene.getEngine().webGLVersion > 1) {
+            defines.setValue("NUM_SAMPLES", this.realTimeFilteringQuality + "u", true);
+        }
 
         // Advanced
         defines.setValue("BRDF_V_HEIGHT_CORRELATED", true);
@@ -834,6 +857,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         }
 
         state._emitFunctionFromInclude("helperFunctions", comments);
+        state._emitFunctionFromInclude("importanceSampling", comments);
         state._emitFunctionFromInclude("pbrHelperFunctions", comments);
         state._emitFunctionFromInclude("imageProcessingFunctions", comments);
 
@@ -851,6 +875,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
 
         state._emitFunctionFromInclude("pbrDirectLightingFalloffFunctions", comments);
         state._emitFunctionFromInclude("pbrBRDFFunctions", comments);
+        state._emitFunctionFromInclude("hdrFilteringFunctions", comments);
 
         state._emitFunctionFromInclude("pbrDirectLightingFunctions", comments, {
             replaceStrings: [
@@ -913,9 +938,18 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
             #else\r\n`;
 
         // _____________________________ Reflectivity _______________________________
+        const subsurfaceBlock = this.subsurface.isConnected ? this.subsurface.connectedPoint?.ownerBlock as SubSurfaceBlock : null;
+        const refractionBlock = this.subsurface.isConnected ? (this.subsurface.connectedPoint?.ownerBlock as SubSurfaceBlock).refraction.connectedPoint?.ownerBlock as RefractionBlock : null;
+
+        const reflectivityBlock = this.reflectivity.connectedPoint?.ownerBlock as Nullable<ReflectivityBlock> ?? null;
+
+        if (reflectivityBlock) {
+            reflectivityBlock.indexOfRefractionConnectionPoint = refractionBlock?.indexOfRefraction ?? null;
+        }
+
         const aoIntensity = aoBlock?.intensity.isConnected ? aoBlock.intensity.associatedVariableName : "1.";
 
-        state.compilationString += (this.reflectivity.connectedPoint?.ownerBlock as Nullable<ReflectivityBlock>)?.getCode(aoIntensity) ?? "";
+        state.compilationString += reflectivityBlock?.getCode(state, aoIntensity) ?? "";
 
         // _____________________________ Geometry info _________________________________
         state.compilationString += state._emitCodeFromInclude("pbrBlockGeometryInfo", comments, {
@@ -949,12 +983,16 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
                 { search: /REFLECTIONMAP_SKYBOX/g, replace: reflectionBlock?._defineSkyboxName ?? "REFLECTIONMAP_SKYBOX" },
                 { search: /LODINREFLECTIONALPHA/g, replace: reflectionBlock?._defineLODReflectionAlpha ?? "LODINREFLECTIONALPHA" },
                 { search: /LINEARSPECULARREFLECTION/g, replace: reflectionBlock?._defineLinearSpecularReflection ?? "LINEARSPECULARREFLECTION" },
+                { search: /vReflectionFilteringInfo/g, replace: reflectionBlock?._vReflectionFilteringInfoName ?? "vReflectionFilteringInfo" },
             ]
         });
 
         // ___________________ Compute Reflectance aka R0 F0 info _________________________
-        state.compilationString += state._emitCodeFromInclude("pbrBlockReflectance0", comments);
-
+        state.compilationString += state._emitCodeFromInclude("pbrBlockReflectance0", comments, {
+            replaceStrings: [
+                { search: /metallicReflectanceFactors/g, replace: reflectivityBlock?._vMetallicReflectanceFactorsName ?? "metallicReflectanceFactors" },
+            ]
+        });
         // ________________________________ Sheen ______________________________
         const sheenBlock = this.sheen.isConnected ? this.sheen.connectedPoint?.ownerBlock as SheenBlock : null;
 
@@ -1006,9 +1044,6 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         });
 
         // ___________________________________ SubSurface ______________________________________
-        const subsurfaceBlock = this.subsurface.isConnected ? this.subsurface.connectedPoint?.ownerBlock as SubSurfaceBlock : null;
-        const refractionBlock = this.subsurface.isConnected ? (this.subsurface.connectedPoint?.ownerBlock as SubSurfaceBlock).refraction.connectedPoint?.ownerBlock as RefractionBlock : null;
-
         state.compilationString += SubSurfaceBlock.GetCode(state, subsurfaceBlock, reflectionBlock, worldPosVarName);
 
         state._emitFunctionFromInclude("pbrBlockSubSurface", comments, {
@@ -1121,6 +1156,8 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         codeString += `${this._codeVariableName}.useRadianceOverAlpha = ${this.useRadianceOverAlpha};\r\n`;
         codeString += `${this._codeVariableName}.useSpecularOverAlpha = ${this.useSpecularOverAlpha};\r\n`;
         codeString += `${this._codeVariableName}.enableSpecularAntiAliasing = ${this.enableSpecularAntiAliasing};\r\n`;
+        codeString += `${this._codeVariableName}.realTimeFiltering = ${this.realTimeFiltering};\r\n`;
+        codeString += `${this._codeVariableName}.realTimeFilteringQuality = ${this.realTimeFilteringQuality};\r\n`;
         codeString += `${this._codeVariableName}.useEnergyConservation = ${this.useEnergyConservation};\r\n`;
         codeString += `${this._codeVariableName}.useRadianceOcclusion = ${this.useRadianceOcclusion};\r\n`;
         codeString += `${this._codeVariableName}.useHorizonOcclusion = ${this.useHorizonOcclusion};\r\n`;
@@ -1149,6 +1186,8 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         serializationObject.useRadianceOverAlpha = this.useRadianceOverAlpha;
         serializationObject.useSpecularOverAlpha = this.useSpecularOverAlpha;
         serializationObject.enableSpecularAntiAliasing = this.enableSpecularAntiAliasing;
+        serializationObject.realTimeFiltering = this.realTimeFiltering;
+        serializationObject.realTimeFilteringQuality = this.realTimeFilteringQuality;
         serializationObject.useEnergyConservation = this.useEnergyConservation;
         serializationObject.useRadianceOcclusion = this.useRadianceOcclusion;
         serializationObject.useHorizonOcclusion = this.useHorizonOcclusion;
@@ -1177,6 +1216,8 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         this.useRadianceOverAlpha = serializationObject.useRadianceOverAlpha;
         this.useSpecularOverAlpha = serializationObject.useSpecularOverAlpha;
         this.enableSpecularAntiAliasing = serializationObject.enableSpecularAntiAliasing;
+        this.realTimeFiltering = !!serializationObject.realTimeFiltering;
+        this.realTimeFilteringQuality = serializationObject.realTimeFilteringQuality ?? Constants.TEXTURE_FILTERING_QUALITY_LOW;
         this.useEnergyConservation = serializationObject.useEnergyConservation;
         this.useRadianceOcclusion = serializationObject.useRadianceOcclusion;
         this.useHorizonOcclusion = serializationObject.useHorizonOcclusion;

+ 11 - 1
src/Materials/Node/Blocks/PBR/reflectionBlock.ts

@@ -15,6 +15,7 @@ import { SubMesh } from '../../../../Meshes/subMesh';
 import { Effect } from '../../../effect';
 import { editableInPropertyPage, PropertyTypeForEdition } from "../../nodeMaterialDecorator";
 import { Scene } from '../../../../scene';
+import { Scalar } from '../../../../Maths/math.scalar';
 
 /**
  * Block used to implement the reflection module of the PBR material
@@ -30,6 +31,8 @@ export class ReflectionBlock extends ReflectionTextureBaseBlock {
     public _vReflectionMicrosurfaceInfosName: string;
     /** @hidden */
     public _vReflectionInfosName: string;
+    /** @hidden */
+    public _vReflectionFilteringInfoName: string;
     private _scene: Scene;
 
     /**
@@ -211,7 +214,10 @@ export class ReflectionBlock extends ReflectionTextureBaseBlock {
             effect.setTexture(this._2DSamplerName, reflectionTexture);
         }
 
-        effect.setFloat3(this._vReflectionMicrosurfaceInfosName, reflectionTexture.getSize().width, reflectionTexture.lodGenerationScale, reflectionTexture.lodGenerationOffset);
+        const width = reflectionTexture.getSize().width;
+
+        effect.setFloat3(this._vReflectionMicrosurfaceInfosName, width, reflectionTexture.lodGenerationScale, reflectionTexture.lodGenerationOffset);
+        effect.setFloat2(this._vReflectionFilteringInfoName, width, Scalar.Log2(width));
 
         const defines = subMesh._materialDefines as  NodeMaterialDefines;
 
@@ -346,6 +352,10 @@ export class ReflectionBlock extends ReflectionTextureBaseBlock {
 
         this._vReflectionInfosName = state._getFreeVariableName("vReflectionInfos");
 
+        this._vReflectionFilteringInfoName = state._getFreeVariableName("vReflectionFilteringInfo");
+
+        state._emitUniformFromString(this._vReflectionFilteringInfoName, "vec2");
+
         code += `#ifdef REFLECTION
             vec2 ${this._vReflectionInfosName} = vec2(1., 0.);
 

+ 46 - 4
src/Materials/Node/Blocks/PBR/reflectivityBlock.ts

@@ -9,12 +9,31 @@ import { NodeMaterialBlockTargets } from '../../Enums/nodeMaterialBlockTargets';
 import { NodeMaterialConnectionPointCustomObject } from "../../nodeMaterialConnectionPointCustomObject";
 import { NodeMaterialConnectionPoint, NodeMaterialConnectionPointDirection } from '../../nodeMaterialBlockConnectionPoint';
 import { Scene } from '../../../../scene';
+import { Nullable } from '../../../../types';
+import { Color3 } from '../../../../Maths/math.color';
+import { TmpColors } from '../../../../Maths/math.color';
+import { Mesh } from '../../../../Meshes/mesh';
+import { SubMesh } from '../../../../Meshes/subMesh';
+import { Effect } from '../../../effect';
 
 /**
  * Block used to implement the reflectivity module of the PBR material
  */
 export class ReflectivityBlock extends NodeMaterialBlock {
 
+    private _metallicReflectanceColor: Color3 = Color3.White();
+    private _metallicF0Factor = 1;
+
+    /** @hidden */
+    public _vMetallicReflectanceFactorsName: string;
+
+    /**
+     * The property below is set by the main PBR block prior to calling methods of this class.
+    */
+
+    /** @hidden */
+    public indexOfRefractionConnectionPoint: Nullable<NodeMaterialConnectionPoint>;
+
     /**
      * Specifies if the metallic texture contains the ambient occlusion information in its red channel.
      */
@@ -103,24 +122,46 @@ export class ReflectivityBlock extends NodeMaterialBlock {
         return this._outputs[0];
     }
 
+    public bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh, subMesh?: SubMesh) {
+        super.bind(effect, nodeMaterial, mesh);
+
+        const outside_ior = 1; // consider air as clear coat and other layers would remap in the shader.
+        const ior = this.indexOfRefractionConnectionPoint?.connectInputBlock?.value ?? 1.5;
+
+        // We are here deriving our default reflectance from a common value for none metallic surface.
+        // Based of the schlick fresnel approximation model
+        // for dielectrics.
+        const f0 = Math.pow((ior - outside_ior) / (ior + outside_ior), 2);
+
+        // Tweak the default F0 and F90 based on our given setup
+        this._metallicReflectanceColor.scaleToRef(f0 * this._metallicF0Factor, TmpColors.Color3[0]);
+        const metallicF90 = this._metallicF0Factor;
+
+        effect.setColor4(this._vMetallicReflectanceFactorsName, TmpColors.Color3[0], metallicF90);
+    }
+
     /**
      * Gets the main code of the block (fragment side)
+     * @param state current state of the node material building
      * @param aoIntensityVarName name of the variable with the ambient occlusion intensity
      * @returns the shader code
      */
-    public getCode(aoIntensityVarName: string): string {
+    public getCode(state: NodeMaterialBuildState, aoIntensityVarName: string): string {
         const metalRoughTexture = this.texture.isConnected ? this.texture.connectedPoint?.associatedVariableName : null;
 
-        // note: metallic F0 factor = 0.04
+        this._vMetallicReflectanceFactorsName = state._getFreeVariableName("vMetallicReflectanceFactors");
+
+        state._emitUniformFromString(this._vMetallicReflectanceFactorsName, "vec4");
+
+        // note: metallic F0 factor = 1
         let code = `vec3 baseColor = surfaceAlbedo;
-            vec4 metallicReflectanceFactors = vec4(1.);
             reflectivityOutParams reflectivityOut;
 
             reflectivityBlock(
                 vec4(${this.metallic.associatedVariableName}, ${this.roughness.associatedVariableName}, 0., 0.),
             #ifdef METALLICWORKFLOW
                 surfaceAlbedo,
-                metallicReflectanceFactors,
+                ${this._vMetallicReflectanceFactorsName},
             #endif
             #ifdef REFLECTIVITY
                 vec3(0., 0., ${aoIntensityVarName}),
@@ -161,6 +202,7 @@ export class ReflectivityBlock extends NodeMaterialBlock {
     protected _buildBlock(state: NodeMaterialBuildState) {
         if (state.target === NodeMaterialBlockTargets.Fragment) {
             state.sharedData.blocksWithDefines.push(this);
+            state.sharedData.bindableBlocks.push(this);
         }
 
         return this;

+ 1 - 1
src/Materials/Node/Blocks/PBR/refractionBlock.ts

@@ -213,7 +213,7 @@ export class RefractionBlock extends NodeMaterialBlock {
             }
         }
 
-        const indexOfRefraction = this.indexOfRefraction.connectInputBlock?.value ?? 1.0;
+        const indexOfRefraction = this.indexOfRefraction.connectInputBlock?.value ?? 1.5;
 
         effect.setFloat4(this._vRefractionInfosName, refractionTexture.level, 1 / indexOfRefraction, depth, this.invertRefractionY ? -1 : 1);
 

TEMPAT SAMPAH
tests/validation/ReferenceImages/node-material-pbr-1.png


+ 5 - 0
tests/validation/config.json

@@ -67,6 +67,11 @@
             "referenceImage": "node-material6.png"
         },    
         {
+            "title": "Node material PBR 1",
+            "playgroundId": "#D8AK3Z#5",
+            "referenceImage": "node-material-pbr-1.png"
+        },    
+        {
             "title": "Basis loader",
             "playgroundId": "#4RN0VF#0",
             "referenceImage": "basis.png"