David Catuhe пре 6 година
родитељ
комит
3fd33d795f

+ 19 - 0
src/Engines/engine.ts

@@ -3510,6 +3510,25 @@ export class Engine {
         var linked = context.getProgramParameter(shaderProgram, context.LINK_STATUS);
 
         if (!linked) {
+            if (this._caps.parallelShaderCompile) { // Get more info
+
+                // Vertex
+                if (!this._gl.getShaderParameter(vertexShader, this._gl.COMPILE_STATUS)) {
+                    let log = this._gl.getShaderInfoLog(vertexShader);
+                    if (log) {
+                        throw new Error(log);
+                    }
+                }
+
+                // Fragment
+                if (!this._gl.getShaderParameter(fragmentShader, this._gl.COMPILE_STATUS)) {
+                    let log = this._gl.getShaderInfoLog(fragmentShader);
+                    if (log) {
+                        throw new Error(log);
+                    }
+                }
+            }
+
             var error = context.getProgramInfoLog(shaderProgram);
             if (error) {
                 throw new Error(error);

+ 5 - 5
src/Materials/Node/Blocks/Dual/fogBlock.ts

@@ -83,10 +83,10 @@ export class FogBlock extends NodeMaterialBlock {
             this.view.setAsWellKnownValue(NodeMaterialWellKnownValues.View);
         }
         if (!this.fogColor.connectedPoint) {
-            this.fogColor.setAsWellKnownValue(NodeMaterialWellKnownValues.FogColor);
+            this.fogColor.setAsWellKnownValue(NodeMaterialWellKnownValues.BlockBased);
         }
         if (!this.fogParameters.connectedPoint) {
-            this.fogParameters.setAsWellKnownValue(NodeMaterialWellKnownValues.FogParameters);
+            this.fogParameters.setAsWellKnownValue(NodeMaterialWellKnownValues.BlockBased);
         }
         this._outputs[0].isVarying = true;
     }
@@ -96,7 +96,7 @@ export class FogBlock extends NodeMaterialBlock {
         defines.setValue("FOG", nodeMaterial.fogEnabled && MaterialHelper.GetFogState(mesh, scene));
     }
 
-    public bind(effect: Effect, mesh?: Mesh) {
+    public bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh) {
         if (!mesh) {
             return;
         }
@@ -112,10 +112,10 @@ export class FogBlock extends NodeMaterialBlock {
         state.sharedData.blocksWithDefines.push(this);
 
         if (state.target === NodeMaterialBlockTargets.Fragment) {
-            state._emitFunctionFromInclude("CalcFogFactor", "fogFragmentDeclaration", {
+            state._emitFunctionFromInclude("fogFragmentDeclaration", {
                 removeUniforms: true,
                 removeVaryings: true,
-                removeifDef: false,
+                removeIfDef: false,
                 replaceStrings: [{ search: /float CalcFogFactor\(\)/, replace: "float CalcFogFactor(vec3 vFogDistance, vec4 vFogInfos)" }]
             });
 

+ 133 - 0
src/Materials/Node/Blocks/Fragment/imageProcessingBlock.ts

@@ -0,0 +1,133 @@
+import { NodeMaterialBlock } from '../../nodeMaterialBlock';
+import { NodeMaterialBlockConnectionPointTypes } from '../../nodeMaterialBlockConnectionPointTypes';
+import { NodeMaterialBuildState } from '../../nodeMaterialBuildState';
+import { NodeMaterialBlockTargets } from '../../nodeMaterialBlockTargets';
+import { NodeMaterialConnectionPoint } from '../../nodeMaterialBlockConnectionPoint';
+import { AbstractMesh } from '../../../../Meshes/abstractMesh';
+import { NodeMaterial, NodeMaterialDefines } from '../../nodeMaterial';
+import { Effect } from '../../../effect';
+import { Mesh } from '../../../../Meshes/mesh';
+
+/**
+ * Block used to add image processing support to fragment shader
+ */
+export class ImageProcessingBlock extends NodeMaterialBlock {
+    /**
+     * Create a new ImageProcessingBlock
+     * @param name defines the block name
+     */
+    public constructor(name: string) {
+        super(name, NodeMaterialBlockTargets.Fragment);
+
+        this.registerInput("color", NodeMaterialBlockConnectionPointTypes.Color3OrColor4);
+        this.registerOutput("output", NodeMaterialBlockConnectionPointTypes.Color4);
+    }
+
+    /**
+     * Gets the current class name
+     * @returns the class name
+     */
+    public getClassName() {
+        return "ImageProcessingBlock";
+    }
+
+    /**
+     * Gets the color input component
+     */
+    public get color(): NodeMaterialConnectionPoint {
+        return this._inputs[0];
+    }
+
+    /**
+     * 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("exposureLinear");
+        state._excludeVariableName("contrast");
+        state._excludeVariableName("vInverseScreenSize");
+        state._excludeVariableName("vignetteSettings1");
+        state._excludeVariableName("vignetteSettings2");
+        state._excludeVariableName("vCameraColorCurveNegative");
+        state._excludeVariableName("vCameraColorCurveNeutral");
+        state._excludeVariableName("vCameraColorCurvePositive");
+        state._excludeVariableName("txColorTransform");
+        state._excludeVariableName("colorTransformSettings");
+    }
+
+    public isReady(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
+        if (defines._areImageProcessingDirty && nodeMaterial.imageProcessingConfiguration) {
+            if (!nodeMaterial.imageProcessingConfiguration.isReady()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
+        if (defines._areImageProcessingDirty && nodeMaterial.imageProcessingConfiguration) {
+            nodeMaterial.imageProcessingConfiguration.prepareDefines(defines);
+        }
+    }
+
+    public bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh) {
+        if (!mesh) {
+            return;
+        }
+
+        if (!nodeMaterial.imageProcessingConfiguration) {
+            return;
+        }
+
+        nodeMaterial.imageProcessingConfiguration.bind(effect);
+    }
+
+    protected _buildBlock(state: NodeMaterialBuildState) {
+        super._buildBlock(state);
+
+        // Register for defines
+        state.sharedData.blocksWithDefines.push(this);
+
+        // Register for blocking
+        state.sharedData.blockingBlocks.push(this);
+
+        // Register for binding
+        state.sharedData.bindableBlocks.push(this);
+
+        // Uniforms
+        state.uniforms.push("exposureLinear");
+        state.uniforms.push("contrast");
+        state.uniforms.push("vInverseScreenSize");
+        state.uniforms.push("vignetteSettings1");
+        state.uniforms.push("vignetteSettings2");
+        state.uniforms.push("vCameraColorCurveNegative");
+        state.uniforms.push("vCameraColorCurveNeutral");
+        state.uniforms.push("vCameraColorCurvePositive");
+        state.uniforms.push("txColorTransform");
+        state.uniforms.push("colorTransformSettings");
+
+        // Emit code
+        let color = this.color;
+        let output = this._outputs[0];
+
+        state._emitFunctionFromInclude("helperFunctions");
+        state._emitFunctionFromInclude("imageProcessingDeclaration");
+        state._emitFunctionFromInclude("imageProcessingFunctions");
+
+        if (color.connectedPoint!.type === NodeMaterialBlockConnectionPointTypes.Color4) {
+            state.compilationString += `${this._declareOutput(output, state)} = ${color.associatedVariableName};\r\n`;
+        } else {
+            state.compilationString += `${this._declareOutput(output, state)} = vec4(${color.associatedVariableName}, 1.0);\r\n`;
+        }
+        state.compilationString += `#ifdef IMAGEPROCESSINGPOSTPROCESS\r\n`;
+        state.compilationString += `${output.associatedVariableName}.rgb = toLinearSpace(${color.associatedVariableName}.rgb);\r\n`;
+        state.compilationString += `#else\r\n`;
+        state.compilationString += `#ifdef IMAGEPROCESSING\r\n`;
+        state.compilationString += `${output.associatedVariableName}.rgb = toLinearSpace(${color.associatedVariableName}.rgb);\r\n`;
+        state.compilationString += `${output.associatedVariableName} = applyImageProcessing(${output.associatedVariableName});\r\n`;
+        state.compilationString += `#endif\r\n`;
+        state.compilationString += `#endif\r\n`;
+
+        return this;
+    }
+}

+ 2 - 1
src/Materials/Node/Blocks/Fragment/index.ts

@@ -5,4 +5,5 @@ export * from "./rgbaMergerBlock";
 export * from "./rgbMergerBlock";
 export * from "./rgbaSplitterBlock";
 export * from "./rgbSplitterBlock";
-export * from "./textureBlock";
+export * from "./textureBlock";
+export * from "./imageProcessingBlock";

+ 14 - 0
src/Materials/Node/Blocks/Fragment/textureBlock.ts

@@ -124,6 +124,15 @@ export class TextureBlock extends NodeMaterialBlock {
         }
     }
 
+    public isReady() {
+        let texture = this.texture.value as BaseTexture;
+        if (texture && !texture.isReadyOrNotBlocking()) {
+            return false;
+        }
+
+        return true;
+    }
+
     private _injectVertexCode(state: NodeMaterialBuildState) {
         let uvInput = this.uv;
         let transformedUV = this.transformedUV;
@@ -142,6 +151,9 @@ export class TextureBlock extends NodeMaterialBlock {
         state._emitUniformOrAttributes(textureTransform, this._defineName);
 
         if (isTextureTransformConnected) {
+            if (state.sharedData.emitComments) {
+                state.compilationString += `\r\n//${this.name}\r\n`;
+            }
             state.compilationString += `#ifdef ${this._defineName}\r\n`;
             state.compilationString += `${transformedUV.associatedVariableName} = vec2(${textureTransform.associatedVariableName} * vec4(${uvInput.associatedVariableName}, 1.0, 0.0));\r\n`;
             state.compilationString += `#else\r\n`;
@@ -155,6 +167,8 @@ export class TextureBlock extends NodeMaterialBlock {
     protected _buildBlock(state: NodeMaterialBuildState) {
         super._buildBlock(state);
 
+        state.sharedData.blockingBlocks.push(this);
+
         // Vertex
         this._injectVertexCode(state._vertexState);
 

+ 3 - 3
src/Materials/Node/Blocks/Vertex/bonesBlock.ts

@@ -108,7 +108,7 @@ export class BonesBlock extends NodeMaterialBlock {
         }
     }
 
-    public bind(effect: Effect, mesh?: Mesh) {
+    public bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh) {
         MaterialHelper.BindBonesParameters(mesh, effect);
     }
 
@@ -138,11 +138,11 @@ export class BonesBlock extends NodeMaterialBlock {
         state.samplers.push("boneSampler");
 
         // Emit code
-        state._emitFunctionFromInclude("BonesDeclaration", "bonesDeclaration", {
+        state._emitFunctionFromInclude("bonesDeclaration", {
             removeAttributes: true,
             removeUniforms: false,
             removeVaryings: true,
-            removeifDef: false
+            removeIfDef: false
         });
 
         let influenceVariablename = state._getFreeVariableName("influence");

+ 2 - 0
src/Materials/Node/Blocks/Vertex/instancesBlock.ts

@@ -94,6 +94,8 @@ export class InstancesBlock extends NodeMaterialBlock {
         if (!this.world.connectedPoint) {
             this.world.setAsWellKnownValue(NodeMaterialWellKnownValues.World);
         }
+
+        this.world.define = "!INSTANCES";
     }
 
     public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines, useInstances: boolean = false) {

+ 89 - 10
src/Materials/Node/nodeMaterial.ts

@@ -10,20 +10,38 @@ import { EffectCreationOptions, EffectFallbacks } from '../effect';
 import { BaseTexture } from '../../Materials/Textures/baseTexture';
 import { NodeMaterialConnectionPoint } from './nodeMaterialBlockConnectionPoint';
 import { NodeMaterialBlockConnectionPointTypes } from './nodeMaterialBlockConnectionPointTypes';
-import { Observable } from '../../Misc/observable';
+import { Observable, Observer } from '../../Misc/observable';
 import { NodeMaterialBlockTargets } from './nodeMaterialBlockTargets';
 import { NodeMaterialBuildStateSharedData } from './NodeMaterialBuildStateSharedData';
 import { SubMesh } from '../../Meshes/subMesh';
 import { MaterialDefines } from '../../Materials/materialDefines';
 import { NodeMaterialOptimizer } from './Optimizers/nodeMaterialOptimizer';
+import { ImageProcessingConfiguration, IImageProcessingConfigurationDefines } from '../imageProcessingConfiguration';
+import { Nullable } from '../../types';
 
 /** @hidden */
-export class NodeMaterialDefines extends MaterialDefines {
+export class NodeMaterialDefines extends MaterialDefines implements IImageProcessingConfigurationDefines {
     /** BONES */
     public NUM_BONE_INFLUENCERS = 0;
     public BonesPerMesh = 0;
     public BONETEXTURE = false;
 
+    /** IMAGE PROCESSING */
+    public IMAGEPROCESSING = false;
+    public VIGNETTE = false;
+    public VIGNETTEBLENDMODEMULTIPLY = false;
+    public VIGNETTEBLENDMODEOPAQUE = false;
+    public TONEMAPPING = false;
+    public TONEMAPPING_ACES = false;
+    public CONTRAST = false;
+    public EXPOSURE = false;
+    public COLORCURVES = false;
+    public COLORGRADING = false;
+    public COLORGRADING3D = false;
+    public SAMPLER3DGREENDEPTH = false;
+    public SAMPLER3DBGRMAP = false;
+    public IMAGEPROCESSINGPOSTPROCESS = false;
+
     constructor() {
         super();
         this.rebuild();
@@ -88,6 +106,30 @@ export class NodeMaterial extends PushMaterial {
     }
 
     /**
+     * Default configuration related to image processing available in the standard Material.
+     */
+    protected _imageProcessingConfiguration: ImageProcessingConfiguration;
+
+    /**
+     * Gets the image processing configuration used either in this material.
+     */
+    public get imageProcessingConfiguration(): ImageProcessingConfiguration {
+        return this._imageProcessingConfiguration;
+    }
+
+    /**
+     * Sets the Default image processing configuration used either in the this material.
+     *
+     * If sets to null, the scene one is in use.
+     */
+    public set imageProcessingConfiguration(value: ImageProcessingConfiguration) {
+        this._attachImageProcessingConfiguration(value);
+
+        // Ensure the effect will be rebuilt.
+        this._markAllSubMeshesAsTexturesDirty();
+    }
+
+    /**
      * Create a new node based material
      * @param name defines the material name
      * @param scene defines the hosting scene
@@ -100,6 +142,9 @@ export class NodeMaterial extends PushMaterial {
             emitComments: false,
             ...options
         };
+
+        // Setup the default processing configuration to the scene.
+        this._attachImageProcessingConfiguration(null);
     }
 
     /**
@@ -111,6 +156,41 @@ export class NodeMaterial extends PushMaterial {
     }
 
     /**
+     * Keep track of the image processing observer to allow dispose and replace.
+     */
+    private _imageProcessingObserver: Nullable<Observer<ImageProcessingConfiguration>>;
+
+    /**
+     * Attaches a new image processing configuration to the Standard Material.
+     * @param configuration
+     */
+    protected _attachImageProcessingConfiguration(configuration: Nullable<ImageProcessingConfiguration>): void {
+        if (configuration === this._imageProcessingConfiguration) {
+            return;
+        }
+
+        // Detaches observer.
+        if (this._imageProcessingConfiguration && this._imageProcessingObserver) {
+            this._imageProcessingConfiguration.onUpdateParameters.remove(this._imageProcessingObserver);
+        }
+
+        // Pick the scene configuration if needed.
+        if (!configuration) {
+            this._imageProcessingConfiguration = this.getScene().imageProcessingConfiguration;
+        }
+        else {
+            this._imageProcessingConfiguration = configuration;
+        }
+
+        // Attaches observer.
+        if (this._imageProcessingConfiguration) {
+            this._imageProcessingObserver = this._imageProcessingConfiguration.onUpdateParameters.add(() => {
+                this._markAllSubMeshesAsImageProcessingDirty();
+            });
+        }
+    }
+
+    /**
      * Adds a new optimizer to the list of optimizers
      * @param optimizer defines the optimizers to add
      * @returns the current material
@@ -338,7 +418,8 @@ export class NodeMaterial extends PushMaterial {
         this._fragmentCompilationState.finalize(this._fragmentCompilationState);
 
         // Textures
-        this._textureConnectionPoints = this._sharedData.uniformConnectionPoints.filter((u) => u.type === NodeMaterialBlockConnectionPointTypes.Texture);
+        this._textureConnectionPoints =
+            this._sharedData.uniformConnectionPoints.filter((u) => u.type === NodeMaterialBlockConnectionPointTypes.Texture || u.type === NodeMaterialBlockConnectionPointTypes.Texture3D);
 
         this._buildId++;
 
@@ -397,12 +478,10 @@ export class NodeMaterial extends PushMaterial {
         }
 
         var engine = scene.getEngine();
-        // Textures
-        for (var connectionPoint of this._textureConnectionPoints) {
-            let texture = connectionPoint.value as BaseTexture;
-            if (texture && !texture.isReadyOrNotBlocking()) {
-                return false;
-            }
+
+        // Check if blocks are ready
+        if (this._sharedData.blockingBlocks.some((b) => !b.isReady(mesh, this, defines, useInstances))) {
+            return false;
         }
 
         // Shared defines
@@ -532,7 +611,7 @@ export class NodeMaterial extends PushMaterial {
             if (effect && scene.getCachedMaterial() !== this) {
                 // Bindable blocks
                 for (var block of sharedData.bindableBlocks) {
-                    block.bind(effect, mesh);
+                    block.bind(effect, this, mesh);
                 }
 
                 // Connection points

+ 14 - 1
src/Materials/Node/nodeMaterialBlock.ts

@@ -127,9 +127,10 @@ export class NodeMaterialBlock {
     /**
      * Bind data to effect. Will only be called for blocks with isBindable === true
      * @param effect defines the effect to bind data to
+     * @param nodeMaterial defines the hosting NodeMaterial
      * @param mesh defines the mesh that will be rendered
      */
-    public bind(effect: Effect, mesh?: Mesh) {
+    public bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh) {
         // Do nothing
     }
 
@@ -295,6 +296,18 @@ export class NodeMaterialBlock {
     }
 
     /**
+     * Checks if the block is ready
+     * @param mesh defines the mesh to be rendered
+     * @param nodeMaterial defines the node material requesting the update
+     * @param defines defines the material defines to update
+     * @param useInstances specifies that instances should be used
+     * @returns true if the block is ready
+     */
+    public isReady(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines, useInstances: boolean = false) {
+        return true;
+    }
+
+    /**
      * Compile the current node and generate the shader code
      * @param state defines the current compilation state (uniforms, samplers, current string)
      * @returns the current block

+ 6 - 6
src/Materials/Node/nodeMaterialBlockConnectionPoint.ts

@@ -43,6 +43,11 @@ export class NodeMaterialConnectionPoint {
      */
     public isOptional: boolean;
 
+    /**
+     * Gets or sets a string indicating that this uniform must be defined under a #ifdef
+     */
+    public define: string;
+
     /** Gets or sets the target of that connection point */
     public target: NodeMaterialBlockTargets = NodeMaterialBlockTargets.VertexAndFragment;
 
@@ -293,12 +298,6 @@ export class NodeMaterialConnectionPoint {
                 case NodeMaterialWellKnownValues.ViewProjection:
                     effect.setMatrix(variableName, scene.getTransformMatrix());
                     break;
-                case NodeMaterialWellKnownValues.FogColor:
-                    effect.setColor3(variableName, scene.fogColor);
-                    break;
-                case NodeMaterialWellKnownValues.FogParameters:
-                    effect.setFloat4(variableName, scene.fogMode, scene.fogStart, scene.fogEnd, scene.fogDensity);
-                    break;
             }
             return;
         }
@@ -333,6 +332,7 @@ export class NodeMaterialConnectionPoint {
                 effect.setMatrix(this.name, value);
                 break;
             case NodeMaterialBlockConnectionPointTypes.Texture:
+            case NodeMaterialBlockConnectionPointTypes.Texture3D:
                 effect.setTexture(this.name, value);
                 break;
         }

+ 2 - 0
src/Materials/Node/nodeMaterialBlockConnectionPointTypes.ts

@@ -20,6 +20,8 @@ export enum NodeMaterialBlockConnectionPointTypes {
     Matrix = 128,
     /** Texture */
     Texture = 256,
+    /** Texture3D */
+    Texture3D = 512,
     /** Vector3 or Color3 */
     Vector3OrColor3 = Vector3 | Color3,
     /** Vector4 or Color4 */

+ 32 - 18
src/Materials/Node/nodeMaterialBuildState.ts

@@ -58,10 +58,11 @@ export class NodeMaterialBuildState {
 
         this.compilationString = `\r\n${emitComments ? "//Entry point\r\n" : ""}void main(void) {\r\n${this.compilationString}`;
 
+        let functionCode = "";
         for (var functionName in this.functions) {
-            let functionCode = this.functions[functionName];
-            this.compilationString = `\r\n${functionCode}\r\n${this.compilationString}`;
+            functionCode += this.functions[functionName] + `\r\n`;
         }
+        this.compilationString = `\r\n${functionCode}\r\n${this.compilationString}`;
 
         if (!isFragmentMode && this._varyingTransfer) {
             this.compilationString = `${this.compilationString}\r\n${this._varyingTransfer}`;
@@ -135,6 +136,8 @@ export class NodeMaterialBuildState {
                 return "mat4";
             case NodeMaterialBlockConnectionPointTypes.Texture:
                 return "sampler2D";
+            case NodeMaterialBlockConnectionPointTypes.Texture3D:
+                return "sampler3D";
         }
 
         return "";
@@ -170,46 +173,47 @@ export class NodeMaterialBuildState {
     }
 
     /** @hidden */
-    public _emitFunctionFromInclude(name: string, includeName: string, options?: {
+    public _emitFunctionFromInclude(includeName: string, options?: {
         removeAttributes?: boolean,
         removeUniforms?: boolean,
         removeVaryings?: boolean,
-        removeifDef?: boolean,
+        removeIfDef?: boolean,
         replaceStrings?: { search: RegExp, replace: string }[],
     }) {
-        if (this.functions[name]) {
+        if (this.functions[includeName]) {
             return;
         }
 
-        this.functions[name] = Effect.IncludesShadersStore[includeName];
-
         if (!options) {
+            this.functions[includeName] = `#include<${includeName}>\r\n`;
             return;
         }
 
-        if (options.removeifDef) {
-            this.functions[name] = this.functions[name].replace(/^\s*?#ifdef.+$/gm, "");
-            this.functions[name] = this.functions[name].replace(/^\s*?#endif.*$/gm, "");
-            this.functions[name] = this.functions[name].replace(/^\s*?#else.*$/gm, "");
-            this.functions[name] = this.functions[name].replace(/^\s*?#elif.*$/gm, "");
+        this.functions[includeName] = Effect.IncludesShadersStore[includeName];
+
+        if (options.removeIfDef) {
+            this.functions[includeName] = this.functions[includeName].replace(/^\s*?#ifdef.+$/gm, "");
+            this.functions[includeName] = this.functions[includeName].replace(/^\s*?#endif.*$/gm, "");
+            this.functions[includeName] = this.functions[includeName].replace(/^\s*?#else.*$/gm, "");
+            this.functions[includeName] = this.functions[includeName].replace(/^\s*?#elif.*$/gm, "");
         }
 
         if (options.removeAttributes) {
-            this.functions[name] = this.functions[name].replace(/^\s*?attribute.+$/gm, "");
+            this.functions[includeName] = this.functions[includeName].replace(/^\s*?attribute.+$/gm, "");
         }
 
         if (options.removeUniforms) {
-            this.functions[name] = this.functions[name].replace(/^\s*?uniform.+$/gm, "");
+            this.functions[includeName] = this.functions[includeName].replace(/^\s*?uniform.+$/gm, "");
         }
 
         if (options.removeVaryings) {
-            this.functions[name] = this.functions[name].replace(/^\s*?varying.+$/gm, "");
+            this.functions[includeName] = this.functions[includeName].replace(/^\s*?varying.+$/gm, "");
         }
 
         if (options.replaceStrings) {
             for (var index = 0; index < options.replaceStrings.length; index++) {
                 let replaceString = options.replaceStrings[index];
-                this.functions[name] = this.functions[name].replace(replaceString.search, replaceString.replace);
+                this.functions[includeName] = this.functions[includeName].replace(replaceString.search, replaceString.replace);
             }
         }
     }
@@ -244,8 +248,18 @@ export class NodeMaterialBuildState {
         }
     }
 
+    private _emitDefine(define: string): string {
+        if (define[0] === "!") {
+            return `#ifndef ${define.substring(1)}\r\n`;
+        }
+
+        return `#ifdef ${define}\r\n`;
+    }
+
     /** @hidden */
     public _emitUniformOrAttributes(point: NodeMaterialConnectionPoint, define?: string) {
+        define = define || point.define;
+
         // Samplers
         if (point.type === NodeMaterialBlockConnectionPointTypes.Texture) {
             point.name = this._getFreeVariableName(point.name);
@@ -257,7 +271,7 @@ export class NodeMaterialBuildState {
 
             this.samplers.push(point.name);
             if (define) {
-                this._uniformDeclaration += `#ifdef ${define}\r\n`;
+                this._uniformDeclaration += this._emitDefine(define);
             }
             this._samplerDeclaration += `uniform ${this._getGLType(point.type)} ${point.name};\r\n`;
             if (define) {
@@ -283,7 +297,7 @@ export class NodeMaterialBuildState {
 
             this.uniforms.push(point.associatedVariableName);
             if (define) {
-                this._uniformDeclaration += `#ifdef ${define}\r\n`;
+                this._uniformDeclaration += this._emitDefine(define);
             }
             this._uniformDeclaration += `uniform ${this._getGLType(point.type)} ${point.associatedVariableName};\r\n`;
             if (define) {

+ 5 - 0
src/Materials/Node/nodeMaterialBuildStateSharedData.ts

@@ -36,6 +36,11 @@ export class NodeMaterialBuildStateSharedData {
     public blocksWithDefines = new Array<NodeMaterialBlock>();
 
     /**
+     * List of blocks that can block the isReady function for the material
+     */
+    public blockingBlocks = new Array<NodeMaterialBlock>();
+
+    /**
      * Build Id used to avoid multiple recompilations
      */
     public buildId: number;

+ 2 - 4
src/Materials/Node/nodeMaterialWellKnownValues.ts

@@ -14,8 +14,6 @@ export enum NodeMaterialWellKnownValues {
     WorldView = 5,
     /** WorldViewProjection */
     WorldViewProjection = 6,
-    /** Fog color */
-    FogColor = 7,
-    /** Fog parameters */
-    FogParameters = 8
+    /** Will be filled by the block itself */
+    BlockBased = 7
 }

+ 3 - 3
src/Materials/standardMaterial.ts

@@ -532,12 +532,12 @@ export class StandardMaterial extends PushMaterial {
             return;
         }
 
-        // Detaches observer.
+        // Detaches observer
         if (this._imageProcessingConfiguration && this._imageProcessingObserver) {
             this._imageProcessingConfiguration.onUpdateParameters.remove(this._imageProcessingObserver);
         }
 
-        // Pick the scene configuration if needed.
+        // Pick the scene configuration if needed
         if (!configuration) {
             this._imageProcessingConfiguration = this.getScene().imageProcessingConfiguration;
         }
@@ -545,7 +545,7 @@ export class StandardMaterial extends PushMaterial {
             this._imageProcessingConfiguration = configuration;
         }
 
-        // Attaches observer.
+        // Attaches observer
         if (this._imageProcessingConfiguration) {
             this._imageProcessingObserver = this._imageProcessingConfiguration.onUpdateParameters.add(() => {
                 this._markAllSubMeshesAsImageProcessingDirty();