Преглед изворни кода

Migrate NodeMaterial to PushMaterial

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

+ 22 - 2
src/Materials/Node/Blocks/Vertex/bonesBlock.ts

@@ -3,8 +3,9 @@ import { NodeMaterialBlockConnectionPointTypes } from '../../nodeMaterialBlockCo
 import { NodeMaterialBuildState } from '../../nodeMaterialBuildState';
 import { NodeMaterialWellKnownValues } from '../../nodeMaterialWellKnownValues';
 import { NodeMaterialBlockTargets } from '../../nodeMaterialBlockTargets';
+import { AbstractMesh } from '../../../../Meshes/abstractMesh';
 import { Mesh } from '../../../../Meshes/mesh';
-import { Effect } from '../../../effect';
+import { Effect, EffectFallbacks } from '../../../effect';
 import { MaterialHelper } from '../../../materialHelper';
 
 /**
@@ -16,7 +17,7 @@ export class BonesBlock extends NodeMaterialBlock {
      * @param name defines the block name
      */
     public constructor(name: string) {
-        super(name, NodeMaterialBlockTargets.Vertex, false, true);
+        super(name, NodeMaterialBlockTargets.Vertex);
 
         this.registerInput("matricesIndices", NodeMaterialBlockConnectionPointTypes.Vector4);
         this.registerInput("matricesWeights", NodeMaterialBlockConnectionPointTypes.Vector4);
@@ -53,6 +54,12 @@ export class BonesBlock extends NodeMaterialBlock {
         return "BonesBlock";
     }
 
+    public provideFallbacks(mesh: AbstractMesh, fallbacks: EffectFallbacks) {
+        if (mesh && mesh.useBones && mesh.computeBonesUsingShaders && mesh.skeleton) {
+            fallbacks.addCPUSkinningFallback(0, mesh);
+        }
+    }
+
     public bind(effect: Effect, mesh?: Mesh) {
         MaterialHelper.BindBonesParameters(mesh, effect);
     }
@@ -60,6 +67,19 @@ export class BonesBlock extends NodeMaterialBlock {
     protected _buildBlock(state: NodeMaterialBuildState) {
         super._buildBlock(state);
 
+        // Register for compilation fallbacks
+        state.sharedData.blocksWithFallbacks.push(this);
+
+        // Register for binding
+        state.sharedData.bindableBlocks.push(this);
+
+        // Register internal uniforms and samplers
+        state.uniforms.push("boneTextureWidth");
+        state.uniforms.push("mBones");
+
+        state.samplers.push("boneSampler");
+
+        // Emit code
         state._emitFunctionFromInclude("BonesDeclaration", "bonesDeclaration", {
             removeAttributes: true,
             removeUniforms: false,

+ 132 - 141
src/Materials/Node/nodeMaterial.ts

@@ -1,5 +1,5 @@
 import { NodeMaterialBlock } from './nodeMaterialBlock';
-import { Material } from '../material';
+import { PushMaterial } from '../pushMaterial';
 import { Scene } from '../../scene';
 import { AbstractMesh } from '../../Meshes/abstractMesh';
 import { Matrix } from '../../Maths/math';
@@ -13,6 +13,9 @@ import { NodeMaterialBlockConnectionPointTypes } from './nodeMaterialBlockConnec
 import { Observable } from '../../Misc/observable';
 import { NodeMaterialBlockTargets } from './nodeMaterialBlockTargets';
 import { NodeMaterialBuildStateSharedData } from './NodeMaterialBuildStateSharedData';
+import { SubMesh } from '../../Meshes/subMesh';
+import { MaterialDefines } from '../../Materials/materialDefines';
+import { MaterialHelper } from '../../Materials/materialHelper';
 
 /**
  * Class used to configure NodeMaterial
@@ -27,13 +30,13 @@ export interface INodeMaterialOptions {
 /**
  * Class used to create a node based material built by assembling shader blocks
  */
-export class NodeMaterial extends Material {
+export class NodeMaterial extends PushMaterial {
     private _options: INodeMaterialOptions;
     private _vertexCompilationState: NodeMaterialBuildState;
     private _fragmentCompilationState: NodeMaterialBuildState;
+    private _sharedData: NodeMaterialBuildStateSharedData;
     private _buildId: number = 0;
-    private _renderId: number;
-    private _effectCompileId: number = 0;
+    private _buildWasSuccessful = false;
     private _cachedWorldViewMatrix = new Matrix();
     private _cachedWorldViewProjectionMatrix = new Matrix();
     private _textureConnectionPoints = new Array<NodeMaterialConnectionPoint>();
@@ -176,7 +179,7 @@ export class NodeMaterial extends Material {
      * @returns a boolean specifying if alpha blending is needed
      */
     public needAlphaBlending(): boolean {
-        return (this.alpha < 1.0) || this._fragmentCompilationState.sharedData.hints.needAlphaBlending;
+        return (this.alpha < 1.0) || this._sharedData.hints.needAlphaBlending;
     }
 
     /**
@@ -184,7 +187,7 @@ export class NodeMaterial extends Material {
      * @returns a boolean specifying if an alpha test is needed.
      */
     public needAlphaTesting(): boolean {
-        return this._fragmentCompilationState.sharedData.hints.needAlphaTesting;
+        return this._sharedData.hints.needAlphaTesting;
     }
 
     private _propagateTarget(node: NodeMaterialBlock, target: NodeMaterialBlockTargets, state: NodeMaterialBuildState) {
@@ -219,6 +222,7 @@ export class NodeMaterial extends Material {
      * @param verbose defines if the build should log activity
      */
     public build(verbose: boolean = false) {
+        this._buildWasSuccessful = false;
         if (this._vertexRootNodes.length === 0) {
             throw "You must define at least one vertexRootNode";
         }
@@ -234,12 +238,12 @@ export class NodeMaterial extends Material {
         this._fragmentCompilationState.target = NodeMaterialBlockTargets.Fragment;
 
         // Shared data
-        let sharedData = new NodeMaterialBuildStateSharedData();
-        this._vertexCompilationState.sharedData = sharedData;
-        this._fragmentCompilationState.sharedData = sharedData;
-        sharedData.buildId = this._buildId;
-        sharedData.emitComments = this._options.emitComments;
-        sharedData.verbose = verbose;
+        this._sharedData = new NodeMaterialBuildStateSharedData();
+        this._vertexCompilationState.sharedData = this._sharedData;
+        this._fragmentCompilationState.sharedData = this._sharedData;
+        this._sharedData.buildId = this._buildId;
+        this._sharedData.emitComments = this._options.emitComments;
+        this._sharedData.verbose = verbose;
 
         // Propagate targets
         for (var vertexRootNode of this._vertexRootNodes) {
@@ -271,12 +275,12 @@ export class NodeMaterial extends Material {
         this._fragmentCompilationState.finalize(this._fragmentCompilationState);
 
         // Textures
-        this._textureConnectionPoints = sharedData.uniformConnectionPoints.filter((u) => u.type === NodeMaterialBlockConnectionPointTypes.Texture);
+        this._textureConnectionPoints = this._sharedData.uniformConnectionPoints.filter((u) => u.type === NodeMaterialBlockConnectionPointTypes.Texture);
 
         this._buildId++;
 
         // Errors
-        sharedData.emitErrors();
+        this._sharedData.emitErrors();
 
         if (verbose) {
             console.log("Vertex shader:");
@@ -285,27 +289,42 @@ export class NodeMaterial extends Material {
             console.log(this._fragmentCompilationState.compilationString);
         }
 
+        this._buildWasSuccessful = true;
         this.onBuildObservable.notifyObservers(this);
     }
 
-    /**
-     * Checks if the material is ready to render the requested mesh
-     * @param mesh defines the mesh to render
-     * @param useInstances defines whether or not the material is used with instances
-     * @returns true if ready, otherwise false
+   /**
+     * Get if the submesh is ready to be used and all its information available.
+     * Child classes can use it to update shaders
+     * @param mesh defines the mesh to check
+     * @param subMesh defines which submesh to check
+     * @param useInstances specifies that instances should be used
+     * @returns a boolean indicating that the submesh is ready or not
      */
-    public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
-        var scene = this.getScene();
-        var engine = scene.getEngine();
-        let defines: string[] = [];
-        var fallbacks = new EffectFallbacks();
+    public isReadyForSubMesh(mesh: AbstractMesh, subMesh: SubMesh, useInstances: boolean = false): boolean {
+        if (!this._buildWasSuccessful) {
+            return false;
+        }
 
-        if (!this.checkReadyOnEveryCall) {
-            if (this._renderId === scene.getRenderId()) {
+        if (subMesh.effect && this.isFrozen) {
+            if (this._wasPreviouslyReady) {
                 return true;
             }
         }
 
+        if (!subMesh._materialDefines) {
+            subMesh._materialDefines = new MaterialDefines();
+        }
+
+        var scene = this.getScene();
+        var defines = subMesh._materialDefines;
+        if (!this.checkReadyOnEveryCall && subMesh.effect) {
+            if (defines._renderId === scene.getRenderId()) {
+                return true;
+            }
+        }
+
+        var engine = scene.getEngine();
         // Textures
         for (var connectionPoint of this._textureConnectionPoints) {
             let texture = connectionPoint.value as BaseTexture;
@@ -314,92 +333,75 @@ export class NodeMaterial extends Material {
             }
         }
 
-        this._renderId = scene.getRenderId();
-
-        if (this._effectCompileId === this._buildId) {
-            return true;
-        }
-
-        var previousEffect = this._effect;
-
-        // Uniforms
-        let mergedUniforms = this._vertexCompilationState.uniforms;
-
-        this._fragmentCompilationState.uniforms.forEach((u) => {
-            let index = mergedUniforms.indexOf(u);
-
-            if (index === -1) {
-                mergedUniforms.push(u);
-            }
-
-        });
-
-        // Samplers
-        let mergedSamplers = this._vertexCompilationState.samplers;
-
-        this._fragmentCompilationState.samplers.forEach((s) => {
-            let index = mergedSamplers.indexOf(s);
-
-            if (index === -1) {
-                mergedSamplers.push(s);
-            }
-        });
-
         // Bones
-        if (mesh && mesh.useBones && mesh.computeBonesUsingShaders && mesh.skeleton) {
-            const skeleton = mesh.skeleton;
+        MaterialHelper.PrepareDefinesForAttributes(mesh, defines, false, true, false, false);
 
-            defines.push("#define NUM_BONE_INFLUENCERS " + mesh.numBoneInfluencers);
-            fallbacks.addCPUSkinningFallback(0, mesh);
+        if (defines.isDirty) {
+            defines.markAsProcessed();
+            // Uniforms
+            let mergedUniforms = this._vertexCompilationState.uniforms;
 
-            if (skeleton.isUsingTextureForMatrices) {
-                defines.push("#define BONETEXTURE");
+            this._fragmentCompilationState.uniforms.forEach((u) => {
+                let index = mergedUniforms.indexOf(u);
 
-                if (mergedUniforms.indexOf("boneTextureWidth") === -1) {
-                    mergedUniforms.push("boneTextureWidth");
+                if (index === -1) {
+                    mergedUniforms.push(u);
                 }
+            });
 
-                if (mergedSamplers.indexOf("boneSampler") === -1) {
-                    mergedSamplers.push("boneSampler");
-                }
-            } else {
-                defines.push("#define BonesPerMesh " + (skeleton.bones.length + 1));
+            // Samplers
+            let mergedSamplers = this._vertexCompilationState.samplers;
 
-                if (mergedUniforms.indexOf("mBones") === -1) {
-                    mergedUniforms.push("mBones");
+            this._fragmentCompilationState.samplers.forEach((s) => {
+                let index = mergedSamplers.indexOf(s);
+
+                if (index === -1) {
+                    mergedSamplers.push(s);
+                }
+            });
+
+            var fallbacks = new EffectFallbacks();
+
+            this._sharedData.blocksWithFallbacks.forEach(b => {
+                b.provideFallbacks(mesh, fallbacks);
+            })
+
+            let previousEffect = subMesh.effect;
+            // Compilation
+            var join = defines.toString();
+            var effect = engine.createEffect({
+                vertex: "nodeMaterial" + this._buildId,
+                fragment: "nodeMaterial" + this._buildId,
+                vertexSource: this._vertexCompilationState.compilationString,
+                fragmentSource: this._fragmentCompilationState.compilationString
+            }, <EffectCreationOptions>{
+                attributes: this._vertexCompilationState.attributes,
+                uniformsNames: mergedUniforms,
+                samplers: mergedSamplers,
+                defines: join,
+                fallbacks: fallbacks,
+                onCompiled: this.onCompiled,
+                onError: this.onError
+            }, engine);
+
+            if (effect) {
+                // Use previous effect while new one is compiling
+                if (this.allowShaderHotSwapping && previousEffect && !effect.isReady()) {
+                    effect = previousEffect;
+                    defines.markAsUnprocessed();
+                } else {
+                    scene.resetCachedMaterial();
+                    subMesh.setEffect(effect, defines);
                 }
             }
-
-        } else {
-            defines.push("#define NUM_BONE_INFLUENCERS 0");
-        }
-
-        // Compilation
-        var join = defines.join("\n");
-        this._effect = engine.createEffect({
-            vertex: "nodeMaterial" + this._buildId,
-            fragment: "nodeMaterial" + this._buildId,
-            vertexSource: this._vertexCompilationState.compilationString,
-            fragmentSource: this._fragmentCompilationState.compilationString
-        }, <EffectCreationOptions>{
-            attributes: this._vertexCompilationState.attributes,
-            uniformsNames: mergedUniforms,
-            samplers: mergedSamplers,
-            defines: join,
-            fallbacks: fallbacks,
-            onCompiled: this.onCompiled,
-            onError: this.onError
-        }, engine);
-
-        if (!this._effect.isReady()) {
-            return false;
         }
 
-        if (previousEffect !== this._effect) {
-            scene.resetCachedMaterial();
+        if (!subMesh.effect || !subMesh.effect.isReady()) {
+            return false;
         }
 
-        this._effectCompileId = this._buildId;
+        defines._renderId = scene.getRenderId();
+        this._wasPreviouslyReady = true;
 
         return true;
     }
@@ -411,72 +413,61 @@ export class NodeMaterial extends Material {
     public bindOnlyWorldMatrix(world: Matrix): void {
         var scene = this.getScene();
 
-        if (!this._effect) {
+        if (!this._activeEffect) {
             return;
         }
 
-        let hints = this._fragmentCompilationState.sharedData.hints;
-        if (hints.needWorldMatrix) {
-            this._effect.setMatrix("world", world);
-        }
+        let hints = this._sharedData.hints;
 
         if (hints.needWorldViewMatrix) {
             world.multiplyToRef(scene.getViewMatrix(), this._cachedWorldViewMatrix);
-            this._effect.setMatrix("worldView", this._cachedWorldViewMatrix);
         }
 
         if (hints.needWorldViewProjectionMatrix) {
             world.multiplyToRef(scene.getTransformMatrix(), this._cachedWorldViewProjectionMatrix);
-            this._effect.setMatrix("worldViewProjection", this._cachedWorldViewProjectionMatrix);
+        }
+
+        // Connection points
+        for (var connectionPoint of this._sharedData.uniformConnectionPoints) {
+            connectionPoint.transmitWorld(this._activeEffect, world, this._cachedWorldViewMatrix, this._cachedWorldViewProjectionMatrix);
         }
     }
 
     /**
-     * Binds the material to the mesh
+     * Binds the submesh to this material by preparing the effect and shader to draw
      * @param world defines the world transformation matrix
-     * @param mesh defines the mesh to bind the material to
+     * @param mesh defines the mesh containing the submesh
+     * @param subMesh defines the submesh to bind the material to
      */
-    public bind(world: Matrix, mesh?: Mesh): void {
+    public bindForSubMesh(world: Matrix, mesh: Mesh, subMesh: SubMesh): void {
         let scene = this.getScene();
-        // Std values
-        this.bindOnlyWorldMatrix(world);
-
-        let sharedData = this._fragmentCompilationState.sharedData;
-        if (this._effect && scene.getCachedMaterial() !== this) {
-            let hints = sharedData.hints;
-
-            if (hints.needViewMatrix) {
-                this._effect.setMatrix("view", scene.getViewMatrix());
-            }
-
-            if (hints.needProjectionMatrix) {
-                this._effect.setMatrix("projection", scene.getProjectionMatrix());
-            }
-
-            if (hints.needViewProjectionMatrix) {
-                this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
-            }
+        var effect = subMesh.effect;
+        if (!effect) {
+            return;
+        }
+        this._activeEffect = effect;
 
-            if (hints.needFogColor) {
-                this._effect.setColor3("fogColor", scene.fogColor);
-            }
+        // Matrices
+        this.bindOnlyWorldMatrix(world);
 
-            if (hints.needFogParameters) {
-                this._effect.setFloat4("fogParameters", scene.fogMode, scene.fogStart, scene.fogEnd, scene.fogDensity);
-            }
+        let mustRebind = this._mustRebind(scene, effect, mesh.visibility);
 
-            // Connection points
-            for (var connectionPoint of sharedData.uniformConnectionPoints) {
-                connectionPoint.transmit(this._effect);
-            }
+        if (mustRebind) {
+            let sharedData = this._sharedData;
+            if (effect && scene.getCachedMaterial() !== this) {
+                // Connection points
+                for (var connectionPoint of sharedData.uniformConnectionPoints) {
+                    connectionPoint.transmit(effect, scene);
+                }
 
-            // Bindable blocks
-            for (var block of sharedData.activeBlocks) {
-                block.bind(this._effect, mesh);
+                // Bindable blocks
+                for (var block of sharedData.bindableBlocks) {
+                    block.bind(effect, mesh);
+                }
             }
         }
 
-        this._afterBind(mesh);
+        this._afterBind(mesh, this._activeEffect);
     }
 
     /**

+ 12 - 16
src/Materials/Node/nodeMaterialBlock.ts

@@ -3,7 +3,8 @@ import { NodeMaterialBuildState } from './nodeMaterialBuildState';
 import { Nullable } from '../../types';
 import { NodeMaterialConnectionPoint } from './nodeMaterialBlockConnectionPoint';
 import { NodeMaterialBlockTargets } from './nodeMaterialBlockTargets';
-import { Effect } from '../effect';
+import { Effect, EffectFallbacks } from '../effect';
+import { AbstractMesh } from '../../Meshes/abstractMesh';
 import { Mesh } from '../../Meshes/mesh';
 
 /**
@@ -13,7 +14,6 @@ export class NodeMaterialBlock {
     private _buildId: number;
     private _target: NodeMaterialBlockTargets;
     private _isFinalMerger = false;
-    private _isBindable = false;
 
     /** @hidden */
     protected _inputs = new Array<NodeMaterialConnectionPoint>();
@@ -33,13 +33,6 @@ export class NodeMaterialBlock {
     }
 
     /**
-     * Gets a boolean indicating that this block needs to bind data to effect
-     */
-    public get isBindable(): boolean {
-        return this._isBindable;
-    }
-
-    /**
      * Gets or sets the build Id
      */
     public get buildId(): number {
@@ -111,13 +104,11 @@ export class NodeMaterialBlock {
      * @param name defines the block name
      * @param target defines the target of that block (Vertex by default)
      * @param isFinalMerger defines a boolean indicating that this block is an end block (e.g. it is generating a system value). Default is false
-     * @param isBindable defines that this block needs to bind data to effect
      */
-    public constructor(name: string, target = NodeMaterialBlockTargets.Vertex, isFinalMerger = false, isBindable = false) {
+    public constructor(name: string, target = NodeMaterialBlockTargets.Vertex, isFinalMerger = false) {
         this.name = name;
 
         this._target = target;
-        this._isBindable = isBindable;
 
         if (isFinalMerger) {
             this._isFinalMerger = true;
@@ -286,6 +277,15 @@ export class NodeMaterialBlock {
     }
 
     /**
+     * Add potential fallbacks if shader compilation fails
+     * @param mesh defines the mesh to be rendered
+     * @param fallbacks defines the current prioritized list of fallbacks
+     */
+    public provideFallbacks(mesh: AbstractMesh, fallbacks: EffectFallbacks) {
+        // Do nothing
+    }
+
+    /**
      * Compile the current node and generate the shader code
      * @param state defines the current compilation state (uniforms, samplers, current string)
      * @returns the current block
@@ -318,10 +318,6 @@ export class NodeMaterialBlock {
             return; // Need to check again as inputs can be connected multiple time to this endpoint
         }
 
-        if (this.isBindable) {
-            state.sharedData.activeBlocks.push(this);
-        }
-
         // Logs
         if (state.sharedData.verbose) {
             console.log(`${state.target === NodeMaterialBlockTargets.Vertex ? "Vertex shader" : "Fragment shader"}: Building ${this.name} [${this.getClassName()}]`);

+ 46 - 27
src/Materials/Node/nodeMaterialBlockConnectionPoint.ts

@@ -3,6 +3,8 @@ import { NodeMaterialBlockTargets } from './nodeMaterialBlockTargets';
 import { Nullable } from '../../types';
 import { Effect } from '../effect';
 import { NodeMaterialWellKnownValues } from './nodeMaterialWellKnownValues';
+import { Scene } from '../../scene';
+import { Matrix } from '../../Maths/math';
 
 declare type NodeMaterialBlock = import("./nodeMaterialBlock").NodeMaterialBlock;
 
@@ -182,32 +184,6 @@ export class NodeMaterialConnectionPoint {
      * @returns the current connection point
      */
     public setAsWellKnownValue(value: NodeMaterialWellKnownValues): NodeMaterialConnectionPoint {
-        switch (value) {
-            case NodeMaterialWellKnownValues.World:
-                this.name = "world";
-                break;
-            case NodeMaterialWellKnownValues.View:
-                this.name = "view";
-                break;
-            case NodeMaterialWellKnownValues.Projection:
-                this.name = "projection";
-                break;
-            case NodeMaterialWellKnownValues.WorldView:
-                this.name = "worldView";
-                break;
-            case NodeMaterialWellKnownValues.WorldViewProjection:
-                this.name = "worldViewProjection";
-                break;
-            case NodeMaterialWellKnownValues.ViewProjection:
-                this.name = "viewProjection";
-                break;
-            case NodeMaterialWellKnownValues.FogColor:
-                this.name = "fogColor";
-                break;
-            case NodeMaterialWellKnownValues.FogParameters:
-                this.name = "fogParameters";
-                break;
-        }
         this.isUniform = true;
         this._wellKnownValue = value;
         return this;
@@ -278,8 +254,51 @@ export class NodeMaterialConnectionPoint {
     /**
      * When connection point is an uniform, this function will send its value to the effect
      * @param effect defines the effect to transmit value to
+     * @param world defines the world matrix
+     * @param worldView defines the worldxview matrix
+     * @param worldViewProjection defines the worldxviewxprojection matrix
+     */
+    public transmitWorld(effect: Effect, world: Matrix, worldView: Matrix, worldViewProjection: Matrix) {
+        switch (this._wellKnownValue) {
+            case NodeMaterialWellKnownValues.World:
+                effect.setMatrix("world", world);
+                break;
+            case NodeMaterialWellKnownValues.WorldView:
+                effect.setMatrix("worldView", worldView);
+                break;
+            case NodeMaterialWellKnownValues.WorldViewProjection:
+                effect.setMatrix("worldViewProjection", worldViewProjection);
+                break;
+        }
+    }
+
+    /**
+     * When connection point is an uniform, this function will send its value to the effect
+     * @param effect defines the effect to transmit value to
+     * @param scene defines the hosting scene
      */
-    public transmit(effect: Effect) {
+    public transmit(effect: Effect, scene: Scene) {
+        if (this._wellKnownValue) {
+            switch (this._wellKnownValue) {
+                case NodeMaterialWellKnownValues.View:
+                    effect.setMatrix("world", scene.getViewMatrix());
+                    break;
+                case NodeMaterialWellKnownValues.Projection:
+                    effect.setMatrix("world", scene.getProjectionMatrix());
+                    break;
+                case NodeMaterialWellKnownValues.ViewProjection:
+                    effect.setMatrix("world", scene.getTransformMatrix());
+                    break;
+                case NodeMaterialWellKnownValues.FogColor:
+                    effect.setColor3("fogColor", scene.fogColor);
+                    break;
+                case NodeMaterialWellKnownValues.FogParameters:
+                    effect.setFloat4("fogParameters", scene.fogMode, scene.fogStart, scene.fogEnd, scene.fogDensity);
+                    break;
+            }
+            return;
+        }
+
         let value = this._valueCallback ? this._valueCallback() : this._storedValue;
 
         switch (this.type) {

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

@@ -254,30 +254,12 @@ export class NodeMaterialBuildState {
             let hints = this.sharedData.hints;
             if (point._wellKnownValue !== null) {
                 switch (point._wellKnownValue) {
-                    case NodeMaterialWellKnownValues.World:
-                        hints.needWorldMatrix = true;
-                        break;
-                    case NodeMaterialWellKnownValues.View:
-                        hints.needViewMatrix = true;
-                        break;
-                    case NodeMaterialWellKnownValues.Projection:
-                        hints.needProjectionMatrix = true;
-                        break;
-                    case NodeMaterialWellKnownValues.ViewProjection:
-                        hints.needViewProjectionMatrix = true;
-                        break;
                     case NodeMaterialWellKnownValues.WorldView:
                         hints.needWorldViewMatrix = true;
                         break;
                     case NodeMaterialWellKnownValues.WorldViewProjection:
                         hints.needWorldViewProjectionMatrix = true;
                         break;
-                    case NodeMaterialWellKnownValues.FogColor:
-                        hints.needFogColor = true;
-                        break;
-                    case NodeMaterialWellKnownValues.FogParameters:
-                        hints.needFogParameters = true;
-                        break;
                 }
             } else {
                 this.sharedData.uniformConnectionPoints.push(point);

+ 7 - 8
src/Materials/Node/nodeMaterialBuildStateSharedData.ts

@@ -21,9 +21,14 @@ export class NodeMaterialBuildStateSharedData {
     public uniformConnectionPoints = new Array<NodeMaterialConnectionPoint>();
 
     /**
-     * Active blocks (Blocks that need to set data to the effect)
+     * Bindable blocks (Blocks that need to set data to the effect)
      */
-    public activeBlocks = new Array<NodeMaterialBlock>();
+    public bindableBlocks = new Array<NodeMaterialBlock>();
+
+    /**
+     * List of blocks that can provide a compilation fallback
+     */
+    public blocksWithFallbacks = new Array<NodeMaterialBlock>();
 
     /**
      * Build Id used to avoid multiple recompilations
@@ -43,14 +48,8 @@ export class NodeMaterialBuildStateSharedData {
      * Gets the compilation hints emitted at compilation time
      */
     public hints = {
-        needWorldMatrix: false,
-        needViewMatrix: false,
-        needProjectionMatrix: false,
-        needViewProjectionMatrix: false,
         needWorldViewMatrix: false,
         needWorldViewProjectionMatrix: false,
-        needFogColor: false,
-        needFogParameters: false,
         needAlphaBlending: false,
         needAlphaTesting: false
     };

+ 2 - 0
src/Materials/materialDefines.ts

@@ -30,6 +30,8 @@ export class MaterialDefines {
     /** @hidden */
     public _needUVs = false;
 
+    [id: string]: any;
+
     /**
      * Specifies if the material needs to be re-calculated
      */