소스 검색

PBR Reflection implementation (WIP)

Popov72 5 년 전
부모
커밋
002527f5b0

+ 102 - 75
src/Materials/Node/Blocks/Dual/reflectionTextureBaseBlock.ts

@@ -22,25 +22,24 @@ import { Texture } from '../../../Textures/texture';
  * Block used to read a reflection texture from a sampler
  */
 export abstract class ReflectionTextureBaseBlock extends NodeMaterialBlock {
-    private _define3DName: string;
-    private _defineCubicName: string;
-    private _defineExplicitName: string;
-    private _defineProjectionName: string;
-    private _defineLocalCubicName: string;
-    private _defineSphericalName: string;
-    private _definePlanarName: string;
-    private _defineEquirectangularName: string;
-    private _defineMirroredEquirectangularFixedName: string;
-    private _defineEquirectangularFixedName: string;
-    private _defineSkyboxName: string;
-    private _cubeSamplerName: string;
-    private _2DSamplerName: string;
-    private _positionUVWName: string;
-    private _directionWName: string;
-    private _reflectionCoordsName: string;
-    private _reflection2DCoordsName: string;
-    private _reflectionMatrixName: string;
-
+    public _define3DName: string;
+    protected _defineCubicName: string;
+    protected _defineExplicitName: string;
+    protected _defineProjectionName: string;
+    protected _defineLocalCubicName: string;
+    protected _defineSphericalName: string;
+    protected _definePlanarName: string;
+    protected _defineEquirectangularName: string;
+    protected _defineMirroredEquirectangularFixedName: string;
+    protected _defineEquirectangularFixedName: string;
+    protected _defineSkyboxName: string;
+    protected _cubeSamplerName: string;
+    protected _2DSamplerName: string;
+    protected _positionUVWName: string;
+    protected _directionWName: string;
+    protected _reflectionVectorName: string;
+    public _reflectionCoordsName: string;
+    protected _reflectionMatrixName: string;
     protected _reflectionColorName: string;
 
     /**
@@ -231,85 +230,113 @@ export abstract class ReflectionTextureBaseBlock extends NodeMaterialBlock {
 
         let comments = `//${this.name}`;
         state._emitFunction("ReciprocalPI", "#define RECIPROCAL_PI2 0.15915494", "");
-        state._emitFunctionFromInclude("reflectionFunction", comments);
+        state._emitFunctionFromInclude("reflectionFunction", comments, {
+            replaceStrings: [
+                { search: /vec3 computeReflectionCoords/g, replace: "void DUMMYFUNC" }
+            ]
+        });
 
         this._reflectionColorName = state._getFreeVariableName("reflectionColor");
-        this._reflectionCoordsName = state._getFreeVariableName("reflectionUVW");
-        this._reflection2DCoordsName = state._getFreeVariableName("reflectionUV");
+        this._reflectionVectorName = state._getFreeVariableName("reflectionUVW");
+        this._reflectionCoordsName = state._getFreeVariableName("reflectionCoords");
         this._reflectionMatrixName = state._getFreeVariableName("reflectionMatrix");
 
         state._emitUniformFromString(this._reflectionMatrixName, "mat4");
     }
 
-    public handleFragmentSideCodeReflectionCoords(): string {
+    public handleFragmentSideCodeReflectionCoords(worldNormalVarName: string): string {
         let worldPos = `v_${this.worldPosition.associatedVariableName}`;
-        let worldNormal = this.worldNormal.associatedVariableName + ".xyz";
         let reflectionMatrix = this._reflectionMatrixName;
         let direction = `normalize(${this._directionWName})`;
         let positionUVW = `${this._positionUVWName}`;
         let vEyePosition = `${this.cameraPosition.associatedVariableName}`;
         let view = `${this.view.associatedVariableName}`;
 
-        let code = "";
-
-        code += `vec3 ${this._reflectionColorName};\r\n`;
-        code += `#ifdef ${this._defineMirroredEquirectangularFixedName}\r\n`;
-        code += `    vec3 ${this._reflectionCoordsName} = computeMirroredFixedEquirectangularCoords(${worldPos}, ${worldNormal}, ${direction});\r\n`;
-        code += `#endif\r\n`;
-
-        code += `#ifdef ${this._defineEquirectangularFixedName}\r\n`;
-        code += `    vec3 ${this._reflectionCoordsName} = computeFixedEquirectangularCoords(${worldPos}, ${worldNormal}, ${direction});\r\n`;
-        code += `#endif\r\n`;
-
-        code += `#ifdef ${this._defineEquirectangularName}\r\n`;
-        code += `    vec3 ${this._reflectionCoordsName} = computeEquirectangularCoords(${worldPos}, ${worldNormal}, ${vEyePosition}.xyz, ${reflectionMatrix});\r\n`;
-        code += ` #endif\r\n`;
+        worldNormalVarName += ".xyz";
+
+        let code = `
+            #ifdef ${this._defineMirroredEquirectangularFixedName}
+                vec3 ${this._reflectionVectorName} = computeMirroredFixedEquirectangularCoords(${worldPos}, ${worldNormalVarName}, ${direction});
+            #endif
+
+            #ifdef ${this._defineEquirectangularFixedName}
+                vec3 ${this._reflectionVectorName} = computeFixedEquirectangularCoords(${worldPos}, ${worldNormalVarName}, ${direction});
+            #endif
+
+            #ifdef ${this._defineEquirectangularName}
+                vec3 ${this._reflectionVectorName} = computeEquirectangularCoords(${worldPos}, ${worldNormalVarName}, ${vEyePosition}.xyz, ${reflectionMatrix});
+            #endif
+
+            #ifdef ${this._defineSphericalName}
+                vec3 ${this._reflectionVectorName} = computeSphericalCoords(${worldPos}, ${worldNormalVarName}, ${view}, ${reflectionMatrix});
+            #endif
+
+            #ifdef ${this._definePlanarName}
+                vec3 ${this._reflectionVectorName} = computePlanarCoords(${worldPos}, ${worldNormalVarName}, ${vEyePosition}.xyz, ${reflectionMatrix});
+            #endif
+
+            #ifdef ${this._defineCubicName}
+                #ifdef ${this._defineLocalCubicName}
+                    vec3 ${this._reflectionVectorName} = computeCubicLocalCoords(${worldPos}, ${worldNormalVarName}, ${vEyePosition}.xyz, ${reflectionMatrix}, vReflectionSize, vReflectionPosition);
+                #else
+                vec3 ${this._reflectionVectorName} = computeCubicCoords(${worldPos}, ${worldNormalVarName}, ${vEyePosition}.xyz, ${reflectionMatrix});
+                #endif
+            #endif
+
+            #ifdef ${this._defineProjectionName}
+                vec3 ${this._reflectionVectorName} = computeProjectionCoords(${worldPos}, ${view}, ${reflectionMatrix});
+            #endif
+
+            #ifdef ${this._defineSkyboxName}
+                vec3 ${this._reflectionVectorName} = computeSkyBoxCoords(${positionUVW}, ${reflectionMatrix});
+            #endif
+
+            #ifdef ${this._defineExplicitName}
+                vec3 ${this._reflectionVectorName} = vec3(0, 0, 0);
+            #endif
+
+            #ifdef ${this._define3DName}
+                vec3 ${this._reflectionCoordsName} = ${this._reflectionVectorName};
+            #else
+                vec2 ${this._reflectionCoordsName} = ${this._reflectionVectorName}.xy;
+                #ifdef ${this._defineProjectionName}
+                    ${this._reflectionCoordsName} /= ${this._reflectionVectorName}.z;
+                #endif
+                ${this._reflectionCoordsName}.y = 1.0 - ${this._reflectionCoordsName}.y;
+            #endif\r\n`;
 
-        code += `#ifdef ${this._defineSphericalName}\r\n`;
-        code += `    vec3 ${this._reflectionCoordsName} = computeSphericalCoords(${worldPos}, ${worldNormal}, ${view}, ${reflectionMatrix});\r\n`;
-        code += `#endif\r\n`;
-
-        code += `#ifdef ${this._definePlanarName}\r\n`;
-        code += `    vec3 ${this._reflectionCoordsName} = computePlanarCoords(${worldPos}, ${worldNormal}, ${vEyePosition}.xyz, ${reflectionMatrix});\r\n`;
-        code += `#endif\r\n`;
-
-        code += `#ifdef ${this._defineCubicName}\r\n`;
-        code += `    #ifdef ${this._defineLocalCubicName}\r\n`;
-        code += `        vec3 ${this._reflectionCoordsName} = computeCubicLocalCoords(${worldPos}, ${worldNormal}, ${vEyePosition}.xyz, ${reflectionMatrix}, vReflectionSize, vReflectionPosition);\r\n`;
-        code += `    #else\r\n`;
-        code += `       vec3 ${this._reflectionCoordsName} = computeCubicCoords(${worldPos}, ${worldNormal}, ${vEyePosition}.xyz, ${reflectionMatrix});\r\n`;
-        code += `    #endif\r\n`;
-        code += `#endif\r\n`;
+        return code;
+    }
 
-        code += `#ifdef ${this._defineProjectionName}\r\n`;
-        code += `    vec3 ${this._reflectionCoordsName} = computeProjectionCoords(${worldPos}, ${view}, ${reflectionMatrix});\r\n`;
-        code += `#endif\r\n`;
+    public handleFragmentSideCodeReflectionColor(lodVarName?: string, swizzleLookupTexture = ".rgb"): string {
+        const colorType = "vec" + (swizzleLookupTexture.length === 0 ? "4" : (swizzleLookupTexture.length - 1));
 
-        code += `#ifdef ${this._defineSkyboxName}\r\n`;
-        code += `    vec3 ${this._reflectionCoordsName} = computeSkyBoxCoords(${positionUVW}, ${reflectionMatrix});\r\n`;
-        code += `#endif\r\n`;
+        let code = `${colorType} ${this._reflectionColorName};
+            #ifdef ${this._define3DName}
+                ${this._reflectionCoordsName} = ${this._reflectionVectorName};\r\n`;
 
-        code += `#ifdef ${this._defineExplicitName}\r\n`;
-        code += `    vec3 ${this._reflectionCoordsName} = vec3(0, 0, 0);\r\n`;
-        code += `#endif\r\n`;
+        if (lodVarName) {
+            code += `${this._reflectionColorName} = textureCubeLodEXT(${this._cubeSamplerName}, ${this._reflectionVectorName}, ${lodVarName})${swizzleLookupTexture};\r\n`;
+        } else {
+            code += `${this._reflectionColorName} = textureCube(${this._cubeSamplerName}, ${this._reflectionVectorName})${swizzleLookupTexture};\r\n`;
+        }
 
-        return code;
-    }
+        code += `
+            #else
+                vec2 ${this._reflectionCoordsName} = ${this._reflectionVectorName}.xy;
 
-    public handleFragmentSideCodeReflectionColor(): string {
-        let code = "";
+                #ifdef ${this._defineProjectionName}
+                    ${this._reflectionCoordsName} /= ${this._reflectionVectorName}.z;
+                #endif
 
-        code += `#ifdef ${this._define3DName}\r\n`;
-        code += `${this._reflectionColorName} = textureCube(${this._cubeSamplerName}, ${this._reflectionCoordsName}).rgb;\r\n`;
-        code += `#else\r\n`;
-        code += `vec2 ${this._reflection2DCoordsName} = ${this._reflectionCoordsName}.xy;\r\n`;
+                ${this._reflectionCoordsName}.y = 1.0 - ${this._reflectionCoordsName}.y;\r\n`;
 
-        code += `#ifdef ${this._defineProjectionName}\r\n`;
-        code += `${this._reflection2DCoordsName} /= ${this._reflectionCoordsName}.z;\r\n`;
-        code += `#endif\r\n`;
+        if (lodVarName) {
+            code += `${this._reflectionColorName} = texture2DLodEXT(${this._2DSamplerName}, ${this._reflectionCoordsName}, ${lodVarName})${swizzleLookupTexture};\r\n`;
+        } else {
+            code += `${this._reflectionColorName} = texture2D(${this._2DSamplerName}, ${this._reflectionCoordsName})${swizzleLookupTexture};\r\n`;
+        }
 
-        code += `${this._reflection2DCoordsName}.y = 1.0 - ${this._reflection2DCoordsName}.y;\r\n`;
-        code += `${this._reflectionColorName} = texture2D(${this._2DSamplerName}, ${this._reflection2DCoordsName}).rgb;\r\n`;
         code += `#endif\r\n`;
 
         return code;

+ 1 - 1
src/Materials/Node/Blocks/Dual/reflectionTextureBlock.ts

@@ -144,7 +144,7 @@ export class ReflectionTextureBlock extends ReflectionTextureBaseBlock {
 
         this.handleFragmentSideInits(state);
 
-        state.compilationString += this.handleFragmentSideCodeReflectionCoords();
+        state.compilationString += this.handleFragmentSideCodeReflectionCoords(this.worldNormal.associatedVariableName);
 
         state.compilationString += this.handleFragmentSideCodeReflectionColor();
 

+ 61 - 11
src/Materials/Node/Blocks/Fragment/PBR/pbrMetallicRoughnessBlock.ts

@@ -119,6 +119,8 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
      * @param state defines the state that will be used for the build
      */
     public initialize(state: NodeMaterialBuildState) {
+        state._excludeVariableName("vLightingIntensity");
+
         state._excludeVariableName("geometricNormalW");
         state._excludeVariableName("normalW");
         state._excludeVariableName("faceNormal");
@@ -136,6 +138,8 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         state._excludeVariableName("seo");
         state._excludeVariableName("eho");
 
+        state._excludeVariableName("environmentRadiance");
+
         state._excludeVariableName("diffuseBase");
         state._excludeVariableName("specularBase");
         state._excludeVariableName("preInfo");
@@ -350,8 +354,6 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
             MaterialHelper.PrepareDefinesForLights(scene, mesh, defines, true, nodeMaterial.maxSimultaneousLights);
             defines._needNormals = true;
 
-            defines.setValue("SPECULARTERM", false); //!! DBG
-
             // Multiview
             //MaterialHelper.PrepareDefinesForMultiview(scene, defines);
         } else {
@@ -486,7 +488,6 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
 
         if (reflectionBlock) {
             reflectionBlock.worldPositionConnectionPoint = this.worldPosition;
-            reflectionBlock.worldNormalConnectionPoint = this.worldNormal;
             reflectionBlock.cameraPositionConnectionPoint = this.cameraPosition;
         }
 
@@ -494,7 +495,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
             // Vertex
             this._injectVertexCode(state);
 
-            return;
+            return this;
         }
 
         // Fragment
@@ -555,7 +556,7 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         state._emitFunctionFromInclude("pbrBlockAmbientOcclusion", comments);
         state._emitFunctionFromInclude("pbrBlockAlphaFresnel", comments);
         state._emitFunctionFromInclude("pbrBlockAnisotropic", comments);
-        state._emitFunctionFromInclude("pbrBlockReflection", comments);
+        //state._emitFunctionFromInclude("pbrBlockReflection", comments);
         state._emitFunctionFromInclude("pbrBlockSheen", comments);
         state._emitFunctionFromInclude("pbrBlockClearcoat", comments);
         state._emitFunctionFromInclude("pbrBlockSubSurface", comments);
@@ -563,7 +564,8 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         //
         // code
         //
-        const vLightingIntensity = "vec4(1.)";
+
+        state.compilationString += `vec4 vLightingIntensity = vec4(1.);\r\n`;
 
         // _____________________________ Geometry Information ____________________________
         if (state._registerTempVariable("viewDirectionW")) {
@@ -607,9 +609,58 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         }
 
         // _____________________________ Reflection _______________________________________
-        reflectionBlock?.handleFragmentSideInits(state);
+        if (reflectionBlock && reflectionBlock.texture) {
+            reflectionBlock.worldNormalConnectionPoint = this.worldNormal;
+
+            state.compilationString += `
+                struct reflectionOutParams
+                {
+                    vec4 environmentRadiance;
+                    vec3 environmentIrradiance;
+                #ifdef ${reflectionBlock._define3DName}
+                    vec3 reflectionCoords;
+                #else
+                    vec2 reflectionCoords;
+                #endif
+                #ifdef SS_TRANSLUCENCY
+                    #ifdef USESPHERICALFROMREFLECTIONMAP
+                        #if !defined(NORMAL) || !defined(USESPHERICALINVERTEX)
+                            vec3 irradianceVector;
+                        #endif
+                    #endif
+                #endif
+                };
+            `;
+
+            state.compilationString += `reflectionOutParams reflectionOut;\r\n`;
+            state.compilationString += reflectionBlock.getCode(state, anisotropyBlock ? "anisotropicOut.anisotropicNormal" : this.worldNormal.associatedVariableName, "environmentRadiance");
+            state.compilationString += `
+                reflectionOut.environmentRadiance = environmentRadiance;
+                reflectionOut.environmentIrradiance = vec3(0.);
+                reflectionOut.reflectionCoords = ${reflectionBlock._reflectionCoordsName};\r\n`;
+        }
+
+        // ___________________ Compute Reflectance aka R0 F0 info _________________________
+        state.compilationString += state._emitCodeFromInclude("pbrBlockReflectance0", comments);
+
+        // ________________________________ Sheen ______________________________
+
+        // _____________________________ Clear Coat ____________________________
+        state.compilationString += `clearcoatOutParams clearcoatOut;
+            #ifdef CLEARCOAT
+            #else
+                clearcoatOut.specularEnvironmentR0 = specularEnvironmentR0;
+            #endif\r\n`;
+
+        // _________________________ Specular Environment Reflectance __________________________
+        state.compilationString += state._emitCodeFromInclude("pbrBlockReflectance", comments);
 
-        state.compilationString += reflectionBlock?.handleFragmentSideCodeReflectionCoords();
+        // ___________________________________ SubSurface ______________________________________
+        state.compilationString += `subSurfaceOutParams subSurfaceOut;
+            #ifdef SUBSURFACE
+            #else
+                subSurfaceOut.specularEnvironmentReflectance = specularEnvironmentReflectance;
+            #endif\r\n`;
 
         // _____________________________ Direct Lighting Info __________________________________
         state.compilationString += state._emitCodeFromInclude("pbrBlockDirectLighting", comments);
@@ -627,13 +678,13 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
         }*/
 
         // _____________________________ Compute Final Lit and Unlit Components ________________________
-        //state.compilationString += state._emitCodeFromInclude("pbrBlockFinalLitComponents", comments);
+        state.compilationString += state._emitCodeFromInclude("pbrBlockFinalLitComponents", comments);
 
         const aoColor = this.ambientColor.isConnected ? this.ambientColor.associatedVariableName : "vec3(0., 0., 0.)";
 
         let aoDirectLightIntensity = aoBlock?.directLightIntensity.isConnected ? aoBlock.directLightIntensity.associatedVariableName : PBRBaseMaterial.DEFAULT_AO_ON_ANALYTICAL_LIGHTS.toString();
 
-        if (!aoBlock?.directLightIntensity.isConnected && aoDirectLightIntensity.charAt(aoDirectLightIntensity.length - 1) !== '.') {
+        if (!aoBlock?.directLightIntensity.isConnected && aoDirectLightIntensity.indexOf('.') === -1) {
             aoDirectLightIntensity += ".";
         }
 
@@ -641,7 +692,6 @@ export class PBRMetallicRoughnessBlock extends NodeMaterialBlock {
             replaceStrings: [
                 { search: /vec3 finalEmissive[\s\S]*?finalEmissive\*=vLightingIntensity\.y;/g, replace: "" },
                 { search: /vAmbientColor/g, replace: aoColor },
-                { search: /vLightingIntensity/g, replace: vLightingIntensity },
                 { search: /vAmbientInfos\.w/g, replace: aoDirectLightIntensity },
             ]
         });

+ 94 - 3
src/Materials/Node/Blocks/Fragment/PBR/reflectionBlock.ts

@@ -1,16 +1,20 @@
-//import { NodeMaterialBlock } from '../../../nodeMaterialBlock';
 import { NodeMaterialBlockConnectionPointTypes } from '../../../Enums/nodeMaterialBlockConnectionPointTypes';
 import { NodeMaterialBuildState } from '../../../nodeMaterialBuildState';
 import { NodeMaterialConnectionPoint, NodeMaterialConnectionPointDirection } from '../../../nodeMaterialBlockConnectionPoint';
 import { NodeMaterialBlockTargets } from '../../../Enums/nodeMaterialBlockTargets';
-//import { Nullable } from "../../../../types";
+import { NodeMaterial, NodeMaterialDefines } from '../../../nodeMaterial';
 import { _TypeStore } from '../../../../../Misc/typeStore';
-//import { editableInPropertyPage } from "../../../nodeMaterialDecorator";
 import { NodeMaterialConnectionPointCustomObject } from "../../../nodeMaterialConnectionPointCustomObject";
 import { ReflectionTextureBaseBlock } from '../../Dual/reflectionTextureBaseBlock';
+import { AbstractMesh } from '../../../../../Meshes/abstractMesh';
+import { Engine } from '../../../../../Engines/engine';
 
 export class ReflectionBlock extends ReflectionTextureBaseBlock {
 
+    private _defineLODReflectionAlpha: string;
+    private _defineLinearSpecularReflection: string;
+    private _defineLODBasedMicroSurface: string;
+
     public worldPositionConnectionPoint: NodeMaterialConnectionPoint;
     public worldNormalConnectionPoint: NodeMaterialConnectionPoint;
     public cameraPositionConnectionPoint: NodeMaterialConnectionPoint;
@@ -23,6 +27,7 @@ export class ReflectionBlock extends ReflectionTextureBaseBlock {
         this.registerInput("position", NodeMaterialBlockConnectionPointTypes.Vector3, false, NodeMaterialBlockTargets.Vertex);
         this.registerInput("world", NodeMaterialBlockConnectionPointTypes.Matrix, false, NodeMaterialBlockTargets.Vertex);
         this.registerInput("view", NodeMaterialBlockConnectionPointTypes.Matrix, false, NodeMaterialBlockTargets.Fragment);
+        this.registerInput("color", NodeMaterialBlockConnectionPointTypes.Color3, true, NodeMaterialBlockTargets.Fragment);
 
         this.registerOutput("reflection", NodeMaterialBlockConnectionPointTypes.Object, NodeMaterialBlockTargets.Fragment, new NodeMaterialConnectionPointCustomObject("reflection", this, NodeMaterialConnectionPointDirection.Output, ReflectionBlock, "ReflectionBlock"));
     }
@@ -77,11 +82,97 @@ export class ReflectionBlock extends ReflectionTextureBaseBlock {
         return this._inputs[2];
     }
 
+    public get color(): NodeMaterialConnectionPoint {
+        return this._inputs[3];
+    }
+
     public get reflection(): NodeMaterialConnectionPoint {
         return this._outputs[0];
     }
 
+    public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
+        super.prepareDefines(mesh, nodeMaterial, defines);
+
+        const reflection = this.texture && this.texture.getTextureMatrix;
+
+        defines.setValue("REFLECTION", reflection);
+
+        if (!reflection) {
+            return;
+        }
+
+        defines.setValue(this._defineLODReflectionAlpha, this.texture!.lodLevelInAlpha);
+        defines.setValue(this._defineLinearSpecularReflection, this.texture!.linearSpecularLOD);
+        defines.setValue(this._defineLODBasedMicroSurface, Engine.LastCreatedScene?.getEngine()?.getCaps().textureLOD ?? false);
+    }
+
+    private _formatNumberForGLSL(val: number): string {
+        let s = val.toString();
+
+        if (s.indexOf('.') === -1) {
+            s += ".";
+        }
+
+        return s;
+    }
+
+    public getCode(state: NodeMaterialBuildState, normalVarName: string, finalColorVarName: string): string {
+        let code = "";
+
+        this.handleFragmentSideInits(state);
+
+        code += this.handleFragmentSideCodeReflectionCoords(normalVarName);
+
+        const varLOD = state._getFreeVariableName("reflectionLOD");
+        const varRequestedLOD = state._getFreeVariableName("requestedReflectionLOD");
+        const varAutomaticLOD = state._getFreeVariableName("automaticReflectionLOD");
+        const varInfos = state._getFreeVariableName("vReflectionMicrosurfaceInfos");
+
+        code += `
+            vec4 ${finalColorVarName} = vec4(0.);
+
+            vec3 ${varInfos} = vec3(${this.texture!.getSize().width}., ${this._formatNumberForGLSL(this.texture!.lodGenerationScale)}, ${this._formatNumberForGLSL(this.texture!.lodGenerationScale)});
+
+            #if defined(${this._defineLODReflectionAlpha}) && !defined(${this._defineSkyboxName})
+                float ${varLOD} = getLodFromAlphaG(${varInfos}.x, alphaG, NdotVUnclamped);
+            #elif defined(${this._defineLinearSpecularReflection})
+                float ${varLOD} = getLinearLodFromRoughness(${varInfos}.x, roughness);
+            #else
+                float ${varLOD} = getLodFromAlphaG(${varInfos}.x, alphaG);
+            #endif
+
+            #ifdef ${this._defineLODBasedMicroSurface}
+                ${varLOD} = ${varLOD} * ${varInfos}.y + ${varInfos}.z;
+
+                #ifdef ${this._defineLODReflectionAlpha}
+                    #ifdef ${this._define3DName}
+                        float ${varAutomaticLOD} = UNPACK_LOD(textureCube(${this._cubeSamplerName}, ${this._reflectionCoordsName}).a);
+                    #else
+                        float ${varAutomaticLOD} = UNPACK_LOD(texture2D(${this._2DSamplerName}, ${this._reflectionCoordsName}).a);
+                    #endif
+                    float ${varRequestedLOD} = max(${varAutomaticLOD}, ${varLOD});
+                #else
+                    float ${varRequestedLOD} = ${varLOD};
+                #endif\r\n`;
+
+        code += this.handleFragmentSideCodeReflectionColor(varRequestedLOD, "");
+
+        code += `
+                ${finalColorVarName} = ${this._reflectionColorName}${this.color.isConnected ? " * vec4(" + this.color.associatedVariableName + ", 1.)" : ""};
+            #else
+                // ***not handled***
+            #endif\r\n`;
+
+        return code;
+    }
+
     protected _buildBlock(state: NodeMaterialBuildState) {
+        if (state.target !== NodeMaterialBlockTargets.Fragment) {
+            this._defineLODReflectionAlpha = state._getFreeDefineName("LODINREFLECTIONALPHA");
+            this._defineLinearSpecularReflection = state._getFreeDefineName("LINEARSPECULARREFLECTION");
+            this._defineLODBasedMicroSurface = state._getFreeDefineName("LODBASEDMICROSFURACE");
+        }
+
         return this;
     }
 }