Explorar o código

Merge pull request #8048 from Popov72/nme-pbr

PBR NME: Support of ClearCoat
David Catuhe %!s(int64=5) %!d(string=hai) anos
pai
achega
f56b5f608d

+ 3 - 0
nodeEditor/src/blockTools.ts

@@ -68,6 +68,7 @@ import { AmbientOcclusionBlock } from 'babylonjs/Materials/Node/Blocks/PBR/ambie
 import { ReflectivityBlock } from 'babylonjs/Materials/Node/Blocks/PBR/reflectivityBlock';
 import { AnisotropyBlock } from 'babylonjs/Materials/Node/Blocks/PBR/anisotropyBlock';
 import { ReflectionBlock } from 'babylonjs/Materials/Node/Blocks/PBR/reflectionBlock';
+import { ClearCoatBlock } from 'babylonjs/Materials/Node/Blocks/PBR/clearCoatBlock';
 
 export class BlockTools {
     public static GetBlockFromString(data: string, scene: Scene, nodeMaterial: NodeMaterial) {
@@ -450,6 +451,8 @@ export class BlockTools {
                 return new AnisotropyBlock("Anisotropy");
             case "ReflectionBlock":
                 return new ReflectionBlock("Reflection");
+            case "ClearCoatBlock":
+                return new ClearCoatBlock("ClearCoat");
         }
 
         return null;

+ 3 - 2
nodeEditor/src/components/nodeList/nodeListComponent.tsx

@@ -122,7 +122,8 @@ export class NodeListComponent extends React.Component<INodeListComponentProps,
         "AmbientOcclusionBlock": "PBR Ambient occlusion block",
         "ReflectivityBlock": "PBR Reflectivity block",
         "AnisotropyBlock": "PBR Anisotropy block",
-        "ReflectionBlock": "PBR Reflection block"
+        "ReflectionBlock": "PBR Reflection block",
+        "ClearCoatBlock": "PBR ClearCoat block",
     };
 
     constructor(props: INodeListComponentProps) {
@@ -151,7 +152,7 @@ export class NodeListComponent extends React.Component<INodeListComponentProps,
             Mesh: ["InstancesBlock", "PositionBlock", "UVBlock", "ColorBlock", "NormalBlock", "PerturbNormalBlock", "NormalBlendBlock" , "TangentBlock", "MatrixIndicesBlock", "MatrixWeightsBlock", "WorldPositionBlock", "WorldNormalBlock", "WorldTangentBlock", "FrontFacingBlock"],
             Noises: ["RandomNumberBlock", "SimplexPerlin3DBlock", "WorleyNoise3DBlock"],
             Output_Nodes: ["VertexOutputBlock", "FragmentOutputBlock", "DiscardBlock"],
-            PBR: ["PBRMetallicRoughnessBlock", "AmbientOcclusionBlock", "AnisotropyBlock", "ReflectionBlock", "ReflectivityBlock", "SheenBlock"],
+            PBR: ["PBRMetallicRoughnessBlock", "AmbientOcclusionBlock", "AnisotropyBlock", "ClearCoatBlock", "ReflectionBlock", "ReflectivityBlock", "SheenBlock"],
             Range: ["ClampBlock", "RemapBlock", "NormalizeBlock"],
             Round: ["RoundBlock", "CeilingBlock", "FloorBlock"],
             Scene: ["FogBlock", "CameraPositionBlock", "FogColorBlock", "ImageProcessingBlock", "LightBlock", "LightInformationBlock", "ViewDirectionBlock"],

+ 1 - 0
src/Materials/Node/Blocks/Fragment/perturbNormalBlock.ts

@@ -186,6 +186,7 @@ export class PerturbNormalBlock extends NodeMaterialBlock {
                 { search: /vBumpUV/g, replace: uv.associatedVariableName},
                 { search: /vPositionW/g, replace: worldPosition.associatedVariableName + ".xyz"},
                 { search: /normalW=/g, replace: this.output.associatedVariableName + ".xyz = " },
+                { search: /mat3\(normalMatrix\)\*normalW/g, replace: "mat3(normalMatrix) * " + this.output.associatedVariableName + ".xyz" },
                 { search: /normalW/g, replace: worldNormal.associatedVariableName + ".xyz" },
                 tangentReplaceString
             ]

+ 304 - 0
src/Materials/Node/Blocks/PBR/clearCoatBlock.ts

@@ -0,0 +1,304 @@
+import { NodeMaterialBlock } from '../../nodeMaterialBlock';
+import { NodeMaterialBlockConnectionPointTypes } from '../../Enums/nodeMaterialBlockConnectionPointTypes';
+import { NodeMaterialBuildState } from '../../nodeMaterialBuildState';
+import { NodeMaterialConnectionPoint, NodeMaterialConnectionPointDirection } from '../../nodeMaterialBlockConnectionPoint';
+import { NodeMaterialBlockTargets } from '../../Enums/nodeMaterialBlockTargets';
+import { _TypeStore } from '../../../../Misc/typeStore';
+import { InputBlock } from '../Input/inputBlock';
+import { NodeMaterialConnectionPointCustomObject } from "../../nodeMaterialConnectionPointCustomObject";
+import { NodeMaterial, NodeMaterialDefines } from '../../nodeMaterial';
+import { AbstractMesh } from '../../../../Meshes/abstractMesh';
+import { ReflectionBlock } from './reflectionBlock';
+import { Scene } from '../../../../scene';
+import { Nullable } from '../../../../types';
+import { Mesh } from '../../../../Meshes/mesh';
+import { SubMesh } from '../../../../Meshes/subMesh';
+import { Effect } from '../../../effect';
+import { PBRMetallicRoughnessBlock } from './pbrMetallicRoughnessBlock';
+import { PerturbNormalBlock } from '../Fragment/perturbNormalBlock';
+
+/**
+ * Block used to implement the clear coat module of the PBR material
+ */
+export class ClearCoatBlock extends NodeMaterialBlock {
+
+    private _scene: Scene;
+
+    /**
+     * Create a new ClearCoatBlock
+     * @param name defines the block name
+     */
+    public constructor(name: string) {
+        super(name, NodeMaterialBlockTargets.Fragment);
+
+        this._isUnique = true;
+
+        this.registerInput("intensity", NodeMaterialBlockConnectionPointTypes.Float, false, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("roughness", NodeMaterialBlockConnectionPointTypes.Float, true, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("ior", NodeMaterialBlockConnectionPointTypes.Float, true, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("texture", NodeMaterialBlockConnectionPointTypes.Color3, true, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("bumpTexture", NodeMaterialBlockConnectionPointTypes.Color4, true, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("uv", NodeMaterialBlockConnectionPointTypes.Vector2, true, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("tintColor", NodeMaterialBlockConnectionPointTypes.Color3, true, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("tintAtDistance", NodeMaterialBlockConnectionPointTypes.Float, true, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("tintThickness", NodeMaterialBlockConnectionPointTypes.Float, true, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("tintTexture", NodeMaterialBlockConnectionPointTypes.Color4, true, NodeMaterialBlockTargets.Fragment);
+
+        this.registerOutput("clearcoat", NodeMaterialBlockConnectionPointTypes.Object, NodeMaterialBlockTargets.Fragment,
+            new NodeMaterialConnectionPointCustomObject("clearcoat", this, NodeMaterialConnectionPointDirection.Output, ClearCoatBlock, "ClearCoatBlock"));
+    }
+
+    /**
+     * Initialize the block and prepare the context for build
+     * @param state defines the state that will be used for the build
+     */
+    public initialize(state: NodeMaterialBuildState) {
+        state._excludeVariableName("clearcoatOut");
+        state._excludeVariableName("vClearCoatParams");
+        state._excludeVariableName("vClearCoatTintParams");
+        state._excludeVariableName("vClearCoatRefractionParams");
+        state._excludeVariableName("vClearCoatTangentSpaceParams");
+    }
+
+    /**
+     * Gets the current class name
+     * @returns the class name
+     */
+    public getClassName() {
+        return "ClearCoatBlock";
+    }
+
+    /**
+     * Gets the intensity input component
+     */
+    public get intensity(): NodeMaterialConnectionPoint {
+        return this._inputs[0];
+    }
+
+    /**
+     * Gets the roughness input component
+     */
+    public get roughness(): NodeMaterialConnectionPoint {
+        return this._inputs[1];
+    }
+
+    /**
+     * Gets the ior input component
+     */
+    public get ior(): NodeMaterialConnectionPoint {
+        return this._inputs[2];
+    }
+
+    /**
+     * Gets the texture input component
+     */
+    public get texture(): NodeMaterialConnectionPoint {
+        return this._inputs[3];
+    }
+
+    /**
+     * Gets the bump texture input component
+     */
+    public get bumpTexture(): NodeMaterialConnectionPoint {
+        return this._inputs[4];
+    }
+
+    /**
+     * Gets the uv input component
+     */
+    public get uv(): NodeMaterialConnectionPoint {
+        return this._inputs[5];
+    }
+
+    /**
+     * Gets the tint color input component
+     */
+    public get tintColor(): NodeMaterialConnectionPoint {
+        return this._inputs[6];
+    }
+
+    /**
+     * Gets the tint "at distance" input component
+     */
+    public get tintAtDistance(): NodeMaterialConnectionPoint {
+        return this._inputs[7];
+    }
+
+    /**
+     * Gets the tint thickness input component
+     */
+    public get tintThickness(): NodeMaterialConnectionPoint {
+        return this._inputs[8];
+    }
+
+    /**
+     * Gets the tint texture input component
+     */
+    public get tintTexture(): NodeMaterialConnectionPoint {
+        return this._inputs[9];
+    }
+
+    /**
+     * Gets the clear coat object output component
+     */
+    public get clearcoat(): NodeMaterialConnectionPoint {
+        return this._outputs[0];
+    }
+
+    public autoConfigure(material: NodeMaterial) {
+        if (!this.intensity.isConnected) {
+            let intensityInput = new InputBlock("ClearCoat intensity", NodeMaterialBlockTargets.Fragment, NodeMaterialBlockConnectionPointTypes.Float);
+            intensityInput.value = 1;
+            intensityInput.output.connectTo(this.intensity);
+        }
+    }
+
+    public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
+        super.prepareDefines(mesh, nodeMaterial, defines);
+
+        defines.setValue("CLEARCOAT", true);
+        defines.setValue("CLEARCOAT_TEXTURE", this.texture.isConnected);
+        defines.setValue("CLEARCOAT_TINT", this.tintColor.isConnected || this.tintThickness.isConnected || this.tintAtDistance.isConnected || this.tintTexture.isConnected);
+        defines.setValue("CLEARCOAT_TINT_TEXTURE", this.tintTexture.isConnected);
+        defines.setValue("CLEARCOAT_BUMP", this.bumpTexture.isConnected);
+        defines.setValue("CLEARCOAT_DEFAULTIOR", this.ior.isConnected ? this.ior.connectInputBlock!.value === 1.5 : false);
+
+    }
+
+    public bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh, subMesh?: SubMesh) {
+        super.bind(effect, nodeMaterial, mesh);
+
+        // Clear Coat Refraction params
+        const indexOfRefraction = this.ior.connectInputBlock?.value ?? 1.5;
+
+        const a = 1 - indexOfRefraction;
+        const b = 1 + indexOfRefraction;
+        const f0 = Math.pow((-a / b), 2); // Schlicks approx: (ior1 - ior2) / (ior1 + ior2) where ior2 for air is close to vacuum = 1.
+        const eta = 1 / indexOfRefraction;
+
+        effect.setFloat4("vClearCoatRefractionParams", f0, eta, a, b);
+
+        // Clear Coat tangent space params
+        const mainPBRBlock = this.clearcoat.hasEndpoints ? this.clearcoat.endpoints[0].ownerBlock as PBRMetallicRoughnessBlock : null;
+        const perturbedNormalBlock = mainPBRBlock?.perturbedNormal.isConnected ? mainPBRBlock.perturbedNormal.connectedPoint!.ownerBlock as PerturbNormalBlock : null;
+
+        if (this._scene._mirroredCameraPosition) {
+            effect.setFloat2("vClearCoatTangentSpaceParams", perturbedNormalBlock?.invertX ? 1.0 : -1.0, perturbedNormalBlock?.invertY ? 1.0 : -1.0);
+        } else {
+            effect.setFloat2("vClearCoatTangentSpaceParams", perturbedNormalBlock?.invertX ? -1.0 : 1.0, perturbedNormalBlock?.invertY ? -1.0 : 1.0);
+        }
+    }
+
+    /**
+     * Gets the main code of the block (fragment side)
+     * @param state current state of the node material building
+     * @param ccBlock instance of a ClearCoatBlock or null if the code must be generated without an active clear coat module
+     * @param reflectionBlock instance of a ReflectionBlock null if the code must be generated without an active reflection module
+     * @param worldPosVarName name of the variable holding the world position
+     * @returns the shader code
+     */
+    public static GetCode(state: NodeMaterialBuildState, ccBlock: Nullable<ClearCoatBlock>, reflectionBlock: Nullable<ReflectionBlock>, worldPosVarName: string): string {
+        let code = "";
+
+        const intensity = ccBlock?.intensity.isConnected ? ccBlock.intensity.associatedVariableName : "1.";
+        const roughness = ccBlock?.roughness.isConnected ? ccBlock.roughness.associatedVariableName : "0.";
+        const texture = ccBlock?.texture.isConnected ? ccBlock.texture.associatedVariableName : "vec2(0.)";
+        const bumpTexture = ccBlock?.bumpTexture.isConnected ? ccBlock.bumpTexture.associatedVariableName : "vec4(0.)";
+        const uv = ccBlock?.uv.isConnected ? ccBlock.uv.associatedVariableName : "vec2(0.)";
+
+        const tintColor = ccBlock?.tintColor.isConnected ? ccBlock.tintColor.associatedVariableName : "vec3(1.)";
+        const tintThickness = ccBlock?.tintThickness.isConnected ? ccBlock.tintThickness.associatedVariableName : "1.";
+        const tintAtDistance = ccBlock?.tintAtDistance.isConnected ? ccBlock.tintAtDistance.associatedVariableName : "1.";
+        const tintTexture = ccBlock?.tintTexture.isConnected ? ccBlock.tintTexture.associatedVariableName : "vec4(0.)";
+
+        if (ccBlock) {
+            state._emitUniformFromString("vClearCoatRefractionParams", "vec4");
+            state._emitUniformFromString("vClearCoatTangentSpaceParams", "vec2");
+        }
+
+        code = `clearcoatOutParams clearcoatOut;
+
+        #ifdef CLEARCOAT
+            vec2 vClearCoatParams = vec2(${intensity}, ${roughness});
+            vec4 vClearCoatTintParams = vec4(${tintColor}, ${tintThickness});
+
+            clearcoatBlock(
+                ${worldPosVarName}.xyz,
+                geometricNormalW,
+                viewDirectionW,
+                vClearCoatParams,
+                specularEnvironmentR0,
+            #ifdef CLEARCOAT_TEXTURE
+                ${texture}.rg,
+            #endif
+            #ifdef CLEARCOAT_TINT
+                vClearCoatTintParams,
+                ${tintAtDistance},
+                vClearCoatRefractionParams,
+                #ifdef CLEARCOAT_TINT_TEXTURE
+                    ${tintTexture},
+                #endif
+            #endif
+            #ifdef CLEARCOAT_BUMP
+                vec2(0., 1.),
+                ${bumpTexture},
+                ${uv},
+                #if defined(TANGENT) && defined(NORMAL)
+                    vTBN,
+                #else
+                    vClearCoatTangentSpaceParams,
+                #endif
+                #ifdef OBJECTSPACE_NORMALMAP
+                    normalMatrix,
+                #endif
+            #endif
+            #if defined(FORCENORMALFORWARD) && defined(NORMAL)
+                faceNormal,
+            #endif
+            #ifdef REFLECTION
+                ${reflectionBlock?._vReflectionMicrosurfaceInfosName},
+                ${reflectionBlock?._vReflectionInfosName},
+                ${reflectionBlock?.reflectionColor},
+                vLightingIntensity,
+                #ifdef ${reflectionBlock?._define3DName}
+                    ${reflectionBlock?._cubeSamplerName},
+                #else
+                    ${reflectionBlock?._2DSamplerName},
+                #endif
+                #ifndef LODBASEDMICROSFURACE
+                    #ifdef ${reflectionBlock?._define3DName}
+                        ${reflectionBlock?._cubeSamplerName},
+                        ${reflectionBlock?._cubeSamplerName},
+                    #else
+                        ${reflectionBlock?._2DSamplerName},
+                        ${reflectionBlock?._2DSamplerName},
+                    #endif
+                #endif
+            #endif
+            #if defined(ENVIRONMENTBRDF) && !defined(${reflectionBlock?._defineSkyboxName})
+                #ifdef RADIANCEOCCLUSION
+                    ambientMonochrome,
+                #endif
+            #endif
+                clearcoatOut
+            );
+        #else
+            clearcoatOut.specularEnvironmentR0 = specularEnvironmentR0;
+        #endif\r\n`;
+
+        return code;
+    }
+
+    protected _buildBlock(state: NodeMaterialBuildState) {
+        this._scene = state.sharedData.scene;
+
+        if (state.target === NodeMaterialBlockTargets.Fragment) {
+            state.sharedData.bindableBlocks.push(this);
+            state.sharedData.blocksWithDefines.push(this);
+        }
+
+        return this;
+    }
+}
+
+_TypeStore.RegisteredTypes["BABYLON.ClearCoatBlock"] = ClearCoatBlock;

+ 1 - 0
src/Materials/Node/Blocks/PBR/index.ts

@@ -4,3 +4,4 @@ export * from "./ambientOcclusionBlock";
 export * from "./reflectivityBlock";
 export * from "./anisotropyBlock";
 export * from "./reflectionBlock";
+export * from "./clearCoatBlock";

+ 132 - 98
src/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.ts

@@ -25,6 +25,7 @@ import { BRDFTextureTools } from '../../../../Misc/brdfTextureTools';
 import { MaterialFlags } from '../../../materialFlags';
 import { AnisotropyBlock } from './anisotropyBlock';
 import { ReflectionBlock } from './reflectionBlock';
+import { ClearCoatBlock } from './clearCoatBlock';
 
 const mapOutputToVariable: { [name: string] : [string, string] } = {
     "ambient":      ["finalAmbient", ""],
@@ -37,7 +38,7 @@ const mapOutputToVariable: { [name: string] : [string, string] } = {
     "sheenInd":     ["sheenOut.finalSheenRadianceScaled",           "!defined(UNLIT) && defined(REFLECTION) && defined(SHEEN) && defined(ENVIRONMENTBRDF)"],
     "clearcoatInd": ["clearcoatOut.finalClearCoatRadianceScaled",   "!defined(UNLIT) && defined(REFLECTION) && defined(CLEARCOAT)"],
     "refraction":   ["subSurfaceOut.finalRefraction",               "!defined(UNLIT) && defined(SS_REFRACTION)"],
-    "lighting":     ["finalColor", ""],
+    "lighting":     ["finalColor.rgb", ""],
     "shadow":       ["shadow", ""],
     "alpha":        ["alpha", ""],
 };
@@ -56,6 +57,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
     private _environmentBRDFTexture: Nullable<BaseTexture> = null;
     private _environmentBrdfSamplerName: string;
     private _vNormalWName: string;
+    private _invertNormalName: string;
 
     /**
      * Create a new ReflectionBlock
@@ -82,7 +84,8 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
             new NodeMaterialConnectionPointCustomObject("reflection", this, NodeMaterialConnectionPointDirection.Input, ReflectionBlock, "ReflectionBlock"));
         this.registerInput("sheen", NodeMaterialBlockConnectionPointTypes.Object, true, NodeMaterialBlockTargets.Fragment,
             new NodeMaterialConnectionPointCustomObject("sheen", this, NodeMaterialConnectionPointDirection.Input, SheenBlock, "SheenBlock"));
-        this.registerInput("clearCoat", NodeMaterialBlockConnectionPointTypes.Object, true, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("clearCoat", NodeMaterialBlockConnectionPointTypes.Object, true, NodeMaterialBlockTargets.Fragment,
+            new NodeMaterialConnectionPointCustomObject("clearcoat", this, NodeMaterialConnectionPointDirection.Input, ClearCoatBlock, "ClearCoatBlock"));
         this.registerInput("subSurface", NodeMaterialBlockConnectionPointTypes.Object, true, NodeMaterialBlockTargets.Fragment);
         this.registerInput("anisotropy", NodeMaterialBlockConnectionPointTypes.Object, true, NodeMaterialBlockTargets.Fragment,
             new NodeMaterialConnectionPointCustomObject("anisotropy", this, NodeMaterialConnectionPointDirection.Input, AnisotropyBlock, "AnisotropyBlock"));
@@ -97,7 +100,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         this.registerOutput("sheenInd", NodeMaterialBlockConnectionPointTypes.Color3, NodeMaterialBlockTargets.Fragment);
         this.registerOutput("clearcoatInd", NodeMaterialBlockConnectionPointTypes.Color3, NodeMaterialBlockTargets.Fragment);
         this.registerOutput("refraction", NodeMaterialBlockConnectionPointTypes.Color3, NodeMaterialBlockTargets.Fragment);
-        this.registerOutput("lighting", NodeMaterialBlockConnectionPointTypes.Color4, NodeMaterialBlockTargets.Fragment);
+        this.registerOutput("lighting", NodeMaterialBlockConnectionPointTypes.Color3, NodeMaterialBlockTargets.Fragment);
         this.registerOutput("shadow", NodeMaterialBlockConnectionPointTypes.Float, NodeMaterialBlockTargets.Fragment);
         this.registerOutput("alpha", NodeMaterialBlockConnectionPointTypes.Float, NodeMaterialBlockTargets.Fragment);
     }
@@ -189,10 +192,16 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
     /**
      * If set to true, no lighting calculations will be applied.
      */
-    @editableInPropertyPage("Unlit", PropertyTypeForEdition.Boolean, "ADVANCED")
+    @editableInPropertyPage("Unlit", PropertyTypeForEdition.Boolean, "ADVANCED", { "notifiers": { "update": true }})
     public unlit: boolean = false;
 
     /**
+     * Force normal to face away from face.
+     */
+    @editableInPropertyPage("Force normal forward", PropertyTypeForEdition.Boolean, "ADVANCED", { "notifiers": { "update": true }})
+    public forceNormalForward: boolean = false;
+
+    /**
      * Defines the material debug mode.
      * It helps seeing only some components of the material while troubleshooting.
      */
@@ -579,6 +588,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         defines.setValue("RADIANCEOCCLUSION", this.useRadianceOcclusion);
         defines.setValue("HORIZONOCCLUSION", this.useHorizonOcclusion);
         defines.setValue("UNLIT", this.unlit);
+        defines.setValue("FORCENORMALFORWARD", this.forceNormalForward);
 
         if (this._environmentBRDFTexture && MaterialFlags.ReflectionTextureEnabled) {
             defines.setValue("ENVIRONMENTBRDF", true);
@@ -650,6 +660,10 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         if (ambientScene) {
             effect.setColor3("ambientFromScene", ambientScene);
         }
+
+        const invertNormal = (scene.useRightHandedSystem === (scene._mirroredCameraPosition != null));
+
+        effect.setFloat(this._invertNormalName, invertNormal ? -1 : 1);
     }
 
     private _injectVertexCode(state: NodeMaterialBuildState) {
@@ -767,7 +781,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         state.sharedData.blocksWithDefines.push(this);
 
         let comments = `//${this.name}`;
-        let worldPos = this.worldPosition;
+        let worldPosVarName = "v_" + this.worldPosition.associatedVariableName;
         let normalShading = this.perturbedNormal;
 
         this._environmentBrdfSamplerName = state._getFreeVariableName("environmentBrdfSampler");
@@ -796,13 +810,13 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
 
         state._emitFunctionFromInclude("shadowsFragmentFunctions", comments, {
             replaceStrings: [
-                { search: /vPositionW/g, replace: "v_" + worldPos.associatedVariableName + ".xyz" }
+                { search: /vPositionW/g, replace: worldPosVarName + ".xyz" }
             ]
         });
 
         state._emitFunctionFromInclude("pbrDirectLightingSetupFunctions", comments, {
             replaceStrings: [
-                { search: /vPositionW/g, replace: "v_" + worldPos.associatedVariableName + ".xyz" }
+                { search: /vPositionW/g, replace: worldPosVarName + ".xyz" }
             ]
         });
 
@@ -811,7 +825,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
 
         state._emitFunctionFromInclude("pbrDirectLightingFunctions", comments, {
             replaceStrings: [
-                { search: /vPositionW/g, replace: "v_" + worldPos.associatedVariableName + ".xyz" }
+                { search: /vPositionW/g, replace: worldPosVarName + ".xyz" }
             ]
         });
 
@@ -822,7 +836,6 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         state._emitFunctionFromInclude("pbrBlockAmbientOcclusion", comments);
         state._emitFunctionFromInclude("pbrBlockAlphaFresnel", comments);
         state._emitFunctionFromInclude("pbrBlockAnisotropic", comments);
-        state._emitFunctionFromInclude("pbrBlockClearcoat", comments);
         state._emitFunctionFromInclude("pbrBlockSubSurface", comments);
 
         //
@@ -837,17 +850,21 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         state.compilationString += `vec4 ${this._vNormalWName} = normalize(${this.worldNormal.associatedVariableName});\r\n`;
 
         if (state._registerTempVariable("viewDirectionW")) {
-            state.compilationString += `vec3 viewDirectionW = normalize(${this.cameraPosition.associatedVariableName} - ${"v_" + worldPos.associatedVariableName}.xyz);\r\n`;
+            state.compilationString += `vec3 viewDirectionW = normalize(${this.cameraPosition.associatedVariableName} - ${worldPosVarName}.xyz);\r\n`;
         }
 
         state.compilationString += `vec3 geometricNormalW = ${this._vNormalWName}.xyz;\r\n`;
 
         state.compilationString += `vec3 normalW = ${normalShading.isConnected ? "normalize(" + normalShading.associatedVariableName + ".xyz)" : "geometricNormalW"};\r\n`;
 
+        this._invertNormalName = state._getFreeVariableName("invertNormal");
+
+        state._emitUniformFromString(this._invertNormalName, "float");
+
         state.compilationString += state._emitCodeFromInclude("pbrBlockNormalFinal", comments, {
             replaceStrings: [
-                { search: /vPositionW/g, replace: worldPos.associatedVariableName },
-                { search: /vEyePosition.w/g, replace: "1." },
+                { search: /vPositionW/g, replace: worldPosVarName + ".xyz" },
+                { search: /vEyePosition.w/g, replace: this._invertNormalName },
             ]
         });
 
@@ -861,109 +878,123 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
 
         state.compilationString += AmbientOcclusionBlock.GetCode(aoBlock);
 
-        if (this.unlit) {
-            state.compilationString += `vec3 diffuseBase = vec3(1., 1., 1.);\r\n`;
-        } else {
-            // _____________________________ Reflectivity _______________________________
-            const aoIntensity = aoBlock?.intensity.isConnected ? aoBlock.intensity.associatedVariableName : "1.";
+        // _____________________________ UNLIT  _______________________________
 
-            state.compilationString += (this.reflectivity.connectedPoint?.ownerBlock as Nullable<ReflectivityBlock>)?.getCode(aoIntensity) ?? "";
+        state.compilationString += `#ifdef UNLIT
+                vec3 diffuseBase = vec3(1., 1., 1.);
+            #else\r\n`;
 
-            // _____________________________ Geometry info _________________________________
-            state.compilationString += state._emitCodeFromInclude("pbrBlockGeometryInfo", comments, {
-                replaceStrings: [
-                    { search: /REFLECTIONMAP_SKYBOX/g, replace: reflectionBlock?._defineSkyboxName ?? "REFLECTIONMAP_SKYBOX" },
-                    { search: /REFLECTIONMAP_3D/g, replace: reflectionBlock?._define3DName ?? "REFLECTIONMAP_3D" },
-                ]
-            });
+        // _____________________________ Reflectivity _______________________________
+        const aoIntensity = aoBlock?.intensity.isConnected ? aoBlock.intensity.associatedVariableName : "1.";
 
-            // _____________________________ Anisotropy _______________________________________
-            const anisotropyBlock = this.anisotropy.isConnected ? this.anisotropy.connectedPoint?.ownerBlock as AnisotropyBlock : null;
+        state.compilationString += (this.reflectivity.connectedPoint?.ownerBlock as Nullable<ReflectivityBlock>)?.getCode(aoIntensity) ?? "";
 
-            if (anisotropyBlock) {
-                anisotropyBlock.worldPositionConnectionPoint = this.worldPosition;
-                anisotropyBlock.worldNormalConnectionPoint = this.worldNormal;
+        // _____________________________ Geometry info _________________________________
+        state.compilationString += state._emitCodeFromInclude("pbrBlockGeometryInfo", comments, {
+            replaceStrings: [
+                { search: /REFLECTIONMAP_SKYBOX/g, replace: reflectionBlock?._defineSkyboxName ?? "REFLECTIONMAP_SKYBOX" },
+                { search: /REFLECTIONMAP_3D/g, replace: reflectionBlock?._define3DName ?? "REFLECTIONMAP_3D" },
+            ]
+        });
 
-                state.compilationString += anisotropyBlock.getCode(state, !this.perturbedNormal.isConnected);
-            }
+        // _____________________________ Anisotropy _______________________________________
+        const anisotropyBlock = this.anisotropy.isConnected ? this.anisotropy.connectedPoint?.ownerBlock as AnisotropyBlock : null;
 
-            // _____________________________ Reflection _______________________________________
-            if (reflectionBlock && reflectionBlock.hasTexture) {
-                state.compilationString += reflectionBlock.getCode(state, anisotropyBlock ? "anisotropicOut.anisotropicNormal" : "normalW");
-            }
+        if (anisotropyBlock) {
+            anisotropyBlock.worldPositionConnectionPoint = this.worldPosition;
+            anisotropyBlock.worldNormalConnectionPoint = this.worldNormal;
 
-            state._emitFunctionFromInclude("pbrBlockReflection", comments, {
-                replaceStrings: [
-                    { search: /computeReflectionCoords/g, replace: "computeReflectionCoordsPBR" },
-                    { search: /REFLECTIONMAP_3D/g, replace: reflectionBlock?._define3DName ?? "REFLECTIONMAP_3D" },
-                    { search: /REFLECTIONMAP_OPPOSITEZ/g, replace: reflectionBlock?._defineOppositeZ ?? "REFLECTIONMAP_OPPOSITEZ" },
-                    { search: /REFLECTIONMAP_PROJECTION/g, replace: reflectionBlock?._defineProjectionName ?? "REFLECTIONMAP_PROJECTION" },
-                    { search: /REFLECTIONMAP_SKYBOX/g, replace: reflectionBlock?._defineSkyboxName ?? "REFLECTIONMAP_SKYBOX" },
-                    { search: /LODINREFLECTIONALPHA/g, replace: reflectionBlock?._defineLODReflectionAlpha ?? "LODINREFLECTIONALPHA" },
-                    { search: /LINEARSPECULARREFLECTION/g, replace: reflectionBlock?._defineLinearSpecularReflection ?? "LINEARSPECULARREFLECTION" },
-                ]
-            });
+            state.compilationString += anisotropyBlock.getCode(state, !this.perturbedNormal.isConnected);
+        }
 
-            // ___________________ Compute Reflectance aka R0 F0 info _________________________
-            state.compilationString += state._emitCodeFromInclude("pbrBlockReflectance0", comments);
+        // _____________________________ Reflection _______________________________________
+        if (reflectionBlock && reflectionBlock.hasTexture) {
+            state.compilationString += reflectionBlock.getCode(state, anisotropyBlock ? "anisotropicOut.anisotropicNormal" : "normalW");
+        }
 
-            // ________________________________ Sheen ______________________________
-            const sheenBlock = this.sheen.isConnected ? this.sheen.connectedPoint?.ownerBlock as SheenBlock : null;
+        state._emitFunctionFromInclude("pbrBlockReflection", comments, {
+            replaceStrings: [
+                { search: /computeReflectionCoords/g, replace: "computeReflectionCoordsPBR" },
+                { search: /REFLECTIONMAP_3D/g, replace: reflectionBlock?._define3DName ?? "REFLECTIONMAP_3D" },
+                { search: /REFLECTIONMAP_OPPOSITEZ/g, replace: reflectionBlock?._defineOppositeZ ?? "REFLECTIONMAP_OPPOSITEZ" },
+                { search: /REFLECTIONMAP_PROJECTION/g, replace: reflectionBlock?._defineProjectionName ?? "REFLECTIONMAP_PROJECTION" },
+                { search: /REFLECTIONMAP_SKYBOX/g, replace: reflectionBlock?._defineSkyboxName ?? "REFLECTIONMAP_SKYBOX" },
+                { search: /LODINREFLECTIONALPHA/g, replace: reflectionBlock?._defineLODReflectionAlpha ?? "LODINREFLECTIONALPHA" },
+                { search: /LINEARSPECULARREFLECTION/g, replace: reflectionBlock?._defineLinearSpecularReflection ?? "LINEARSPECULARREFLECTION" },
+            ]
+        });
 
-            if (sheenBlock) {
-                state.compilationString += sheenBlock.getCode(reflectionBlock);
-            }
+        // ___________________ Compute Reflectance aka R0 F0 info _________________________
+        state.compilationString += state._emitCodeFromInclude("pbrBlockReflectance0", comments);
 
-            state._emitFunctionFromInclude("pbrBlockSheen", comments, {
-                replaceStrings: [
-                    { search: /REFLECTIONMAP_3D/g, replace: reflectionBlock?._define3DName ?? "REFLECTIONMAP_3D" },
-                    { search: /REFLECTIONMAP_SKYBOX/g, replace: reflectionBlock?._defineSkyboxName ?? "REFLECTIONMAP_SKYBOX" },
-                    { search: /LODINREFLECTIONALPHA/g, replace: reflectionBlock?._defineLODReflectionAlpha ?? "LODINREFLECTIONALPHA" },
-                    { search: /LINEARSPECULARREFLECTION/g, replace: reflectionBlock?._defineLinearSpecularReflection ?? "LINEARSPECULARREFLECTION" },
-                ]
-            });
+        // ________________________________ Sheen ______________________________
+        const sheenBlock = this.sheen.isConnected ? this.sheen.connectedPoint?.ownerBlock as SheenBlock : null;
+
+        if (sheenBlock) {
+            state.compilationString += sheenBlock.getCode(reflectionBlock);
+        }
+
+        state._emitFunctionFromInclude("pbrBlockSheen", comments, {
+            replaceStrings: [
+                { search: /REFLECTIONMAP_3D/g, replace: reflectionBlock?._define3DName ?? "REFLECTIONMAP_3D" },
+                { search: /REFLECTIONMAP_SKYBOX/g, replace: reflectionBlock?._defineSkyboxName ?? "REFLECTIONMAP_SKYBOX" },
+                { search: /LODINREFLECTIONALPHA/g, replace: reflectionBlock?._defineLODReflectionAlpha ?? "LODINREFLECTIONALPHA" },
+                { search: /LINEARSPECULARREFLECTION/g, replace: reflectionBlock?._defineLinearSpecularReflection ?? "LINEARSPECULARREFLECTION" },
+            ]
+        });
+
+        // _____________________________ Clear Coat ____________________________
+        const clearcoatBlock = this.clearcoat.isConnected ? this.clearcoat.connectedPoint?.ownerBlock as ClearCoatBlock : null;
+
+        state.compilationString += ClearCoatBlock.GetCode(state, clearcoatBlock, reflectionBlock, worldPosVarName);
+
+        state._emitFunctionFromInclude("pbrBlockClearcoat", comments, {
+            replaceStrings: [
+                { search: /computeReflectionCoords/g, replace: "computeReflectionCoordsPBR" },
+                { search: /REFLECTIONMAP_3D/g, replace: reflectionBlock?._define3DName ?? "REFLECTIONMAP_3D" },
+                { search: /REFLECTIONMAP_OPPOSITEZ/g, replace: reflectionBlock?._defineOppositeZ ?? "REFLECTIONMAP_OPPOSITEZ" },
+                { search: /REFLECTIONMAP_PROJECTION/g, replace: reflectionBlock?._defineProjectionName ?? "REFLECTIONMAP_PROJECTION" },
+                { search: /REFLECTIONMAP_SKYBOX/g, replace: reflectionBlock?._defineSkyboxName ?? "REFLECTIONMAP_SKYBOX" },
+                { search: /LODINREFLECTIONALPHA/g, replace: reflectionBlock?._defineLODReflectionAlpha ?? "LODINREFLECTIONALPHA" },
+                { search: /LINEARSPECULARREFLECTION/g, replace: reflectionBlock?._defineLinearSpecularReflection ?? "LINEARSPECULARREFLECTION" },
+            ]
+        });
 
-            // _____________________________ Clear Coat ____________________________
-            state.compilationString += `clearcoatOutParams clearcoatOut;
-                #ifdef CLEARCOAT
-                #else
-                    clearcoatOut.specularEnvironmentR0 = specularEnvironmentR0;
-                #endif\r\n`;
+        // _________________________ Specular Environment Reflectance __________________________
+        state.compilationString += state._emitCodeFromInclude("pbrBlockReflectance", comments, {
+            replaceStrings: [
+                { search: /REFLECTIONMAP_SKYBOX/g, replace: reflectionBlock?._defineSkyboxName ?? "REFLECTIONMAP_SKYBOX" },
+                { search: /REFLECTIONMAP_3D/g, replace: reflectionBlock?._define3DName ?? "REFLECTIONMAP_3D" },
+            ]
+        });
 
-            // _________________________ Specular Environment Reflectance __________________________
-            state.compilationString += state._emitCodeFromInclude("pbrBlockReflectance", comments, {
+        // ___________________________________ SubSurface ______________________________________
+        state.compilationString += `subSurfaceOutParams subSurfaceOut;
+            #ifdef SUBSURFACE
+            #else
+                subSurfaceOut.specularEnvironmentReflectance = specularEnvironmentReflectance;
+            #endif\r\n`;
+
+        // _____________________________ Direct Lighting Info __________________________________
+        state.compilationString += state._emitCodeFromInclude("pbrBlockDirectLighting", comments);
+
+        if (this.light) {
+            state.compilationString += state._emitCodeFromInclude("lightFragment", comments, {
                 replaceStrings: [
-                    { search: /REFLECTIONMAP_SKYBOX/g, replace: reflectionBlock?._defineSkyboxName ?? "REFLECTIONMAP_SKYBOX" },
-                    { search: /REFLECTIONMAP_3D/g, replace: reflectionBlock?._define3DName ?? "REFLECTIONMAP_3D" },
+                    { search: /{X}/g, replace: this._lightId.toString() }
                 ]
             });
+        } else {
+            state.compilationString += state._emitCodeFromInclude("lightFragment", comments, {
+                repeatKey: "maxSimultaneousLights"
+            });
+        }
 
-            // ___________________________________ SubSurface ______________________________________
-            state.compilationString += `subSurfaceOutParams subSurfaceOut;
-                #ifdef SUBSURFACE
-                #else
-                    subSurfaceOut.specularEnvironmentReflectance = specularEnvironmentReflectance;
-                #endif\r\n`;
-
-            // _____________________________ Direct Lighting Info __________________________________
-            state.compilationString += state._emitCodeFromInclude("pbrBlockDirectLighting", comments);
-
-            if (this.light) {
-                state.compilationString += state._emitCodeFromInclude("lightFragment", comments, {
-                    replaceStrings: [
-                        { search: /{X}/g, replace: this._lightId.toString() }
-                    ]
-                });
-            } else {
-                state.compilationString += state._emitCodeFromInclude("lightFragment", comments, {
-                    repeatKey: "maxSimultaneousLights"
-                });
-            }
-
-            // _____________________________ Compute Final Lit Components ________________________
-            state.compilationString += state._emitCodeFromInclude("pbrBlockFinalLitComponents", comments);
+        // _____________________________ Compute Final Lit Components ________________________
+        state.compilationString += state._emitCodeFromInclude("pbrBlockFinalLitComponents", comments);
 
-        } // UNLIT
+        // _____________________________ UNLIT (2) ________________________
+        state.compilationString += `#endif\r\n`; // UNLIT
 
         // _____________________________ Compute Final Unlit Components ________________________
         const aoColor = this.ambientColor.isConnected ? this.ambientColor.associatedVariableName : "vec3(0., 0., 0.)";
@@ -1000,7 +1031,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         state.compilationString += state._emitCodeFromInclude("pbrDebug", comments, {
             replaceStrings: [
                 { search: /vNormalW/g, replace: this._vNormalWName },
-                { search: /vPositionW/g, replace: "v_" + this.worldPosition.associatedVariableName },
+                { search: /vPositionW/g, replace: worldPosVarName },
                 { search: /albedoTexture\.rgb;/g, replace: this.baseTexture.associatedVariableName + ".rgb;\r\ngl_FragColor.rgb = toGammaSpace(gl_FragColor.rgb);\r\n" },
                 { search: /opacityMap/g, replace: this.opacityTexture.associatedVariableName },
             ]
@@ -1046,6 +1077,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         codeString += `${this._codeVariableName}.useRadianceOcclusion = ${this.useRadianceOcclusion};\r\n`;
         codeString += `${this._codeVariableName}.useHorizonOcclusion = ${this.useHorizonOcclusion};\r\n`;
         codeString += `${this._codeVariableName}.unlit = ${this.unlit};\r\n`;
+        codeString += `${this._codeVariableName}.forceNormalForward = ${this.forceNormalForward};\r\n`;
         codeString += `${this._codeVariableName}.debugMode = ${this.debugMode};\r\n`;
         codeString += `${this._codeVariableName}.debugLimit = ${this.debugLimit};\r\n`;
         codeString += `${this._codeVariableName}.debugFactor = ${this.debugFactor};\r\n`;
@@ -1073,6 +1105,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         serializationObject.useRadianceOcclusion = this.useRadianceOcclusion;
         serializationObject.useHorizonOcclusion = this.useHorizonOcclusion;
         serializationObject.unlit = this.unlit;
+        serializationObject.forceNormalForward = this.forceNormalForward;
         serializationObject.debugMode = this.debugMode;
         serializationObject.debugLimit = this.debugLimit;
         serializationObject.debugFactor = this.debugFactor;
@@ -1100,6 +1133,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         this.useRadianceOcclusion = serializationObject.useRadianceOcclusion;
         this.useHorizonOcclusion = serializationObject.useHorizonOcclusion;
         this.unlit = serializationObject.unlit;
+        this.forceNormalForward = !!serializationObject.forceNormalForward;
         this.debugMode = serializationObject.debugMode;
         this.debugLimit = serializationObject.debugLimit;
         this.debugFactor = serializationObject.debugFactor;

+ 8 - 13
src/Shaders/ShadersInclude/pbrBlockClearcoat.fx

@@ -34,26 +34,22 @@ struct clearcoatOutParams
         const in vec3 geometricNormalW,
         const in vec3 viewDirectionW,
         const in vec2 vClearCoatParams,
-        const in vec2 uvOffset,
         const in vec3 specularEnvironmentR0,
     #ifdef CLEARCOAT_TEXTURE
-        const in vec2 vClearCoatUV,
-        const in vec2 vClearCoatInfos,
-        const in sampler2D clearCoatSampler,
+        const in vec2 clearCoatMapData,
     #endif
     #ifdef CLEARCOAT_TINT
         const in vec4 vClearCoatTintParams,
         const in float clearCoatColorAtDistance,
         const in vec4 vClearCoatRefractionParams,
         #ifdef CLEARCOAT_TINT_TEXTURE
-            const in vec2 vClearCoatTintUV_,
-            const in sampler2D clearCoatTintSampler,
+            const in vec4 clearCoatTintMapData,
         #endif
     #endif
     #ifdef CLEARCOAT_BUMP
         const in vec2 vClearCoatBumpInfos,
-        const in vec2 vClearCoatBumpUV_,
-        const in sampler2D clearCoatBumpSampler,
+        const in vec4 clearCoatBumpMapData,
+        const in vec2 vClearCoatBumpUV,
         #if defined(TANGENT) && defined(NORMAL)
             const in mat3 vTBN,
         #else
@@ -68,6 +64,7 @@ struct clearcoatOutParams
     #endif
     #ifdef REFLECTION
         const in vec3 vReflectionMicrosurfaceInfos,
+        const in vec2 vReflectionInfos,
         const in vec3 vReflectionColor,
         const in vec4 vLightingIntensity,
         #ifdef REFLECTIONMAP_3D
@@ -98,7 +95,6 @@ struct clearcoatOutParams
         float clearCoatRoughness = vClearCoatParams.y;
 
         #ifdef CLEARCOAT_TEXTURE
-            vec2 clearCoatMapData = texture2D(clearCoatSampler, vClearCoatUV + uvOffset).rg * vClearCoatInfos.y;
             clearCoatIntensity *= clearCoatMapData.x;
             clearCoatRoughness *= clearCoatMapData.y;
             #if DEBUGMODE > 0
@@ -114,8 +110,7 @@ struct clearcoatOutParams
             float clearCoatThickness = vClearCoatTintParams.a;
 
             #ifdef CLEARCOAT_TINT_TEXTURE
-                vec4 clearCoatTintMapData = texture2D(clearCoatTintSampler, vClearCoatTintUV_ + uvOffset);
-                clearCoatColor *= toLinearSpace(clearCoatTintMapData.rgb);
+                clearCoatColor *= clearCoatTintMapData.rgb;
                 clearCoatThickness *= clearCoatTintMapData.a;
                 #if DEBUGMODE > 0
                     outParams.clearCoatTintMapData = clearCoatTintMapData;
@@ -155,10 +150,10 @@ struct clearcoatOutParams
             #endif
 
             #ifdef OBJECTSPACE_NORMALMAP
-                clearCoatNormalW = normalize(texture2D(clearCoatBumpSampler, vClearCoatBumpUV + uvOffset).xyz  * 2.0 - 1.0);
+                clearCoatNormalW = normalize(clearCoatBumpMapData.xyz  * 2.0 - 1.0);
                 clearCoatNormalW = normalize(mat3(normalMatrix) * clearCoatNormalW);
             #else
-                clearCoatNormalW = perturbNormal(TBNClearCoat, texture2D(clearCoatBumpSampler, vClearCoatBumpUV + uvOffset).xyz, vClearCoatBumpInfos.y);
+                clearCoatNormalW = perturbNormal(TBNClearCoat, clearCoatBumpMapData.xyz, vClearCoatBumpInfos.y);
             #endif
         #endif
 

+ 16 - 7
src/Shaders/pbr.fragment.fx

@@ -311,31 +311,39 @@ void main(void) {
     clearcoatOutParams clearcoatOut;
 
     #ifdef CLEARCOAT
+        #ifdef CLEARCOAT_TEXTURE
+            vec2 clearCoatMapData = texture2D(clearCoatSampler, vClearCoatUV + uvOffset).rg * vClearCoatInfos.y;
+        #endif
+
+        #if defined(CLEARCOAT_TINT) && defined(CLEARCOAT_TINT_TEXTURE)
+            vec4 clearCoatTintMapData = toLinearSpace(texture2D(clearCoatTintSampler, vClearCoatTintUV + uvOffset));
+        #endif
+
+        #ifdef CLEARCOAT_BUMP
+            vec4 clearCoatBumpMapData = texture2D(clearCoatBumpSampler, vClearCoatBumpUV + uvOffset);
+        #endif
+
         clearcoatBlock(
             vPositionW,
             geometricNormalW,
             viewDirectionW,
             vClearCoatParams,
-            uvOffset,
             specularEnvironmentR0,
         #ifdef CLEARCOAT_TEXTURE
-            vClearCoatUV,
-            vClearCoatInfos,
-            clearCoatSampler,
+            clearCoatMapData,
         #endif
         #ifdef CLEARCOAT_TINT
             vClearCoatTintParams,
             clearCoatColorAtDistance,
             vClearCoatRefractionParams,
             #ifdef CLEARCOAT_TINT_TEXTURE
-                vClearCoatTintUV,
-                clearCoatTintSampler,
+                clearCoatTintMapData,
             #endif
         #endif
         #ifdef CLEARCOAT_BUMP
             vClearCoatBumpInfos,
+            clearCoatBumpMapData,
             vClearCoatBumpUV,
-            clearCoatBumpSampler,
             #if defined(TANGENT) && defined(NORMAL)
                 vTBN,
             #else
@@ -350,6 +358,7 @@ void main(void) {
         #endif
         #ifdef REFLECTION
             vReflectionMicrosurfaceInfos,
+            vReflectionInfos,
             vReflectionColor,
             vLightingIntensity,
             reflectionSampler,