Bläddra i källkod

morphsTargetBlock

David Catuhe 6 år sedan
förälder
incheckning
543dbef08b

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

@@ -112,7 +112,7 @@ export class FogBlock extends NodeMaterialBlock {
         state.sharedData.blocksWithDefines.push(this);
 
         if (state.target === NodeMaterialBlockTargets.Fragment) {
-            state._emitFunctionFromInclude("fogFragmentDeclaration", {
+            state._emitFunctionFromInclude("fogFragmentDeclaration", `//${this.name}`, {
                 removeUniforms: true,
                 removeVaryings: true,
                 removeIfDef: false,

+ 4 - 3
src/Materials/Node/Blocks/Fragment/imageProcessingBlock.ts

@@ -109,10 +109,11 @@ export class ImageProcessingBlock extends NodeMaterialBlock {
         // Emit code
         let color = this.color;
         let output = this._outputs[0];
+        let comments = `//${this.name}`;
 
-        state._emitFunctionFromInclude("helperFunctions");
-        state._emitFunctionFromInclude("imageProcessingDeclaration");
-        state._emitFunctionFromInclude("imageProcessingFunctions");
+        state._emitFunctionFromInclude("helperFunctions", comments);
+        state._emitFunctionFromInclude("imageProcessingDeclaration", comments);
+        state._emitFunctionFromInclude("imageProcessingFunctions", comments);
 
         if (color.connectedPoint!.type === NodeMaterialBlockConnectionPointTypes.Color4) {
             state.compilationString += `${this._declareOutput(output, state)} = ${color.associatedVariableName};\r\n`;

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

@@ -138,7 +138,8 @@ export class BonesBlock extends NodeMaterialBlock {
         state.samplers.push("boneSampler");
 
         // Emit code
-        state._emitFunctionFromInclude("bonesDeclaration", {
+        let comments = `//${this.name}`;
+        state._emitFunctionFromInclude("bonesDeclaration", comments, {
             removeAttributes: true,
             removeUniforms: false,
             removeVaryings: true,
@@ -147,7 +148,7 @@ export class BonesBlock extends NodeMaterialBlock {
 
         let influenceVariablename = state._getFreeVariableName("influence");
 
-        state.compilationString += state._emitCodeFromInclude("bonesVertex", {
+        state.compilationString += state._emitCodeFromInclude("bonesVertex", comments, {
             replaceStrings: [
                 {
                     search: /finalWorld=finalWorld\*influence;/,

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

@@ -1,3 +1,4 @@
 export * from "./vertexOutputBlock";
 export * from "./bonesBlock";
-export * from "./instancesBlock";
+export * from "./instancesBlock";
+export * from "./morphTargetsBlock";

+ 211 - 0
src/Materials/Node/Blocks/Vertex/morphTargetsBlock.ts

@@ -0,0 +1,211 @@
+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';
+import { MaterialHelper } from '../../../materialHelper';
+import { VertexBuffer } from '../../../../Meshes/buffer';
+
+/**
+ * Block used to add morph targets support to vertex shader
+ */
+export class MorphTargetsBlock extends NodeMaterialBlock {
+    private _repeatableContentAnchor: string;
+    private _repeatebleContentGenerated = 0;
+
+    /**
+     * Create a new MorphTargetsBlock
+     * @param name defines the block name
+     */
+    public constructor(name: string) {
+        super(name, NodeMaterialBlockTargets.Vertex);
+
+        this.registerInput("position", NodeMaterialBlockConnectionPointTypes.Vector3);
+        this.registerInput("normal", NodeMaterialBlockConnectionPointTypes.Vector3);
+        this.registerInput("tangent", NodeMaterialBlockConnectionPointTypes.Vector3);
+        this.registerOutput("positionOutput", NodeMaterialBlockConnectionPointTypes.Vector3);
+        this.registerOutput("normalOutput", NodeMaterialBlockConnectionPointTypes.Vector3);
+        this.registerOutput("tangentOutput", NodeMaterialBlockConnectionPointTypes.Vector3);
+    }
+
+    /**
+     * Gets the current class name
+     * @returns the class name
+     */
+    public getClassName() {
+        return "MorphTargetsBlock";
+    }
+
+    /**
+     * Gets the position input component
+     */
+    public get position(): NodeMaterialConnectionPoint {
+        return this._inputs[0];
+    }
+
+    /**
+     * Gets the normal input component
+     */
+    public get normal(): NodeMaterialConnectionPoint {
+        return this._inputs[1];
+    }
+
+    /**
+     * Gets the tangent input component
+     */
+    public get tangent(): NodeMaterialConnectionPoint {
+        return this._inputs[2];
+    }
+
+    /**
+     * Gets the position output component
+     */
+    public get positionOutput(): NodeMaterialConnectionPoint {
+        return this._outputs[0];
+    }
+
+    /**
+     * Gets the normal output component
+     */
+    public get normalOutput(): NodeMaterialConnectionPoint {
+        return this._outputs[1];
+    }
+
+    /**
+     * Gets the tangent output component
+     */
+    public get tangentOutput(): NodeMaterialConnectionPoint {
+        return this._outputs[2];
+    }
+
+    public initialize(state: NodeMaterialBuildState) {
+        state._excludeVariableName("morphTargetInfluences");
+    }
+
+    public autoConfigure() {
+        if (!this.position.connectedPoint) {
+            this.position.setAsAttribute();
+        }
+        if (!this.normal.connectedPoint) {
+            this.normal.setAsAttribute();
+            this.normal.define = "NORMAL";
+        }
+        if (!this.tangent.connectedPoint) {
+            this.tangent.setAsAttribute();
+            this.tangent.define = "TANGENT";
+        }
+    }
+
+    public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: NodeMaterialDefines) {
+        if (!defines._areAttributesDirty) {
+            return;
+        }
+        MaterialHelper.PrepareDefinesForMorphTargets(mesh, defines);
+    }
+
+    public bind(effect: Effect, nodeMaterial: NodeMaterial, mesh?: Mesh) {
+        if (mesh && this._repeatebleContentGenerated) {
+            MaterialHelper.BindMorphTargetParameters(mesh, effect);
+        }
+    }
+
+    public replaceRepeatableContent(vertexShaderState: NodeMaterialBuildState, fragmentShaderState: NodeMaterialBuildState, mesh: AbstractMesh, defines: NodeMaterialDefines) {
+        let position = this.position;
+        let normal = this.normal;
+        let tangent = this.tangent;
+        let positionOutput = this.positionOutput;
+        let normalOutput = this.normalOutput;
+        let tangentOutput = this.tangentOutput;
+        let state = vertexShaderState;
+        let repeatCount = defines.NUM_MORPH_INFLUENCERS as number;
+        this._repeatebleContentGenerated = repeatCount;
+
+        var manager = (<Mesh>mesh).morphTargetManager;
+        var hasNormals = manager && manager.supportsNormals && defines["NORMAL"];
+        var hasTangents = manager && manager.supportsTangents && defines["TANGENT"];
+
+        let injectionCode = "";
+
+        for (var index = 0; index < repeatCount; index++) {
+            injectionCode += `#ifdef MORPHTARGETS\r\n`;
+            injectionCode += `${positionOutput.associatedVariableName} += (position${index} - ${position.associatedVariableName}) * morphTargetInfluences[${index}];\r\n`;
+
+            if (hasNormals) {
+                injectionCode += `#ifdef MORPHTARGETS_NORMAL\r\n`;
+                injectionCode += `${normalOutput.associatedVariableName} += (normal${index} - ${normal.associatedVariableName}) * morphTargetInfluences[${index}];\r\n`;
+                injectionCode += `#endif\r\n`;
+            }
+
+            if (hasTangents) {
+                injectionCode += `#ifdef MORPHTARGETS_TANGENT\r\n`;
+                injectionCode += `${tangentOutput.associatedVariableName}.xyz += (tangent${index} - ${tangent.associatedVariableName}.xyz) * morphTargetInfluences[${index}];\r\n`;
+                injectionCode += `#endif\r\n`;
+            }
+
+            injectionCode += `#endif\r\n`;
+        }
+
+        state.compilationString = state.compilationString.replace(this._repeatableContentAnchor, injectionCode);
+
+        if (repeatCount > 0) {
+            for (var index = 0; index < repeatCount; index++) {
+                state.attributes.push(VertexBuffer.PositionKind + index);
+
+                if (hasNormals) {
+                    state.attributes.push(VertexBuffer.NormalKind + index);
+                }
+
+                if (hasTangents) {
+                    state.attributes.push(VertexBuffer.TangentKind + index);
+                }
+            }
+        }
+    }
+
+    protected _buildBlock(state: NodeMaterialBuildState) {
+        super._buildBlock(state);
+
+        // Register for defines
+        state.sharedData.blocksWithDefines.push(this);
+
+        // Register for binding
+        state.sharedData.bindableBlocks.push(this);
+
+        // Register for repeatable content generation
+        state.sharedData.repeatableContentBlocks.push(this);
+
+        // Emit code
+        let position = this.position;
+        let normal = this.normal;
+        let tangent = this.tangent;
+        let positionOutput = this.positionOutput;
+        let normalOutput = this.normalOutput;
+        let tangentOutput = this.tangentOutput;
+        let comments = `//${this.name}`;
+
+        state.uniforms.push("morphTargetInfluences");
+
+        state._emitFunctionFromInclude("morphTargetsVertexGlobalDeclaration", comments);
+        state._emitFunctionFromInclude("morphTargetsVertexDeclaration", comments, {
+            repeatKey: "maxSimultaneousMorphTargets"
+        });
+
+        state.compilationString += `${this._declareOutput(positionOutput, state)} = ${position.associatedVariableName};\r\n`;
+        state.compilationString += `#ifdef NORMAL\r\n`;
+        state.compilationString += `${this._declareOutput(normalOutput, state)} = ${normal.associatedVariableName};\r\n`;
+        state.compilationString += `#endif\r\n`;
+        state.compilationString += `#ifdef TANGENT\r\n`;
+        state.compilationString += `${this._declareOutput(tangentOutput, state)} = ${tangent.associatedVariableName};\r\n`;
+        state.compilationString += `#endif\r\n`;
+
+        // Repeatable content
+        this._repeatableContentAnchor = state._repeatableContentAnchor;
+        state.compilationString += this._repeatableContentAnchor;
+
+        return this;
+    }
+}

+ 10 - 2
src/Materials/Node/Blocks/vector4TransformBlock.ts

@@ -8,6 +8,10 @@ import { NodeMaterialConnectionPoint } from '../nodeMaterialBlockConnectionPoint
  * Block used to transform a vector4 with a matrix
  */
 export class Vector4TransformBlock extends NodeMaterialBlock {
+    /**
+     * Defines the value to use to complement Vector3 to transform it to a Vector4
+     */
+    public complementW = 1;
 
     /**
      * Creates a new Vector4TransformBlock
@@ -16,7 +20,7 @@ export class Vector4TransformBlock extends NodeMaterialBlock {
     public constructor(name: string) {
         super(name, NodeMaterialBlockTargets.Vertex);
 
-        this.registerInput("vector", NodeMaterialBlockConnectionPointTypes.Vector4);
+        this.registerInput("vector", NodeMaterialBlockConnectionPointTypes.Vector3OrVector4);
         this.registerInput("transform", NodeMaterialBlockConnectionPointTypes.Matrix);
         this.registerOutput("output", NodeMaterialBlockConnectionPointTypes.Vector4);
     }
@@ -50,7 +54,11 @@ export class Vector4TransformBlock extends NodeMaterialBlock {
         let vector = this.vector;
         let transform = this.transform;
 
-        state.compilationString += this._declareOutput(output, state) + ` = ${transform.associatedVariableName} * ${vector.associatedVariableName};\r\n`;
+        if (vector.connectedPoint!.type === NodeMaterialBlockConnectionPointTypes.Vector3) {
+            state.compilationString += this._declareOutput(output, state) + ` = ${transform.associatedVariableName} * vec4(${vector.associatedVariableName}, ${this._writeFloat(this.complementW)});\r\n`;
+        } else {
+            state.compilationString += this._declareOutput(output, state) + ` = ${transform.associatedVariableName} * ${vector.associatedVariableName};\r\n`;
+        }
 
         return this;
     }

+ 37 - 1
src/Materials/Node/nodeMaterial.ts

@@ -18,6 +18,7 @@ import { MaterialDefines } from '../../Materials/materialDefines';
 import { NodeMaterialOptimizer } from './Optimizers/nodeMaterialOptimizer';
 import { ImageProcessingConfiguration, IImageProcessingConfigurationDefines } from '../imageProcessingConfiguration';
 import { Nullable } from '../../types';
+import { VertexBuffer } from '../../Meshes/buffer';
 
 /** @hidden */
 export class NodeMaterialDefines extends MaterialDefines implements IImageProcessingConfigurationDefines {
@@ -26,6 +27,12 @@ export class NodeMaterialDefines extends MaterialDefines implements IImageProces
     public BonesPerMesh = 0;
     public BONETEXTURE = false;
 
+    /** MORPH TARGETS */
+    public MORPHTARGETS = false;
+    public MORPHTARGETS_NORMAL = false;
+    public MORPHTARGETS_TANGENT = false;
+    public NUM_MORPH_INFLUENCERS = 0;
+
     /** IMAGE PROCESSING */
     public IMAGEPROCESSING = false;
     public VIGNETTE = false;
@@ -82,6 +89,11 @@ export class NodeMaterial extends PushMaterial {
     private _optimizers = new Array<NodeMaterialOptimizer>();
 
     /**
+    * Defines the maximum number of lights that can be used in the material
+    */
+    public maxSimultaneousLights = 4;
+
+    /**
      * Observable raised when the material is built
      */
     public onBuildObservable = new Observable<NodeMaterial>();
@@ -446,6 +458,18 @@ export class NodeMaterial extends PushMaterial {
         }
     }
 
+    private _prepareDefinesForAttributes(mesh: AbstractMesh, defines: NodeMaterialDefines) {
+        if (!defines._areAttributesDirty && defines._needNormals === defines._normals && defines._needUVs === defines._uvs) {
+            return;
+        }
+
+        defines._normals = defines._needNormals;
+        defines._uvs = defines._needUVs;
+
+        defines.setValue("NORMAL", (defines._needNormals && mesh.isVerticesDataPresent(VertexBuffer.NormalKind)));
+        defines.setValue("TANGENT", mesh.isVerticesDataPresent(VertexBuffer.TangentKind));
+    }
+
     /**
       * Get if the submesh is ready to be used and all its information available.
       * Child classes can use it to update shaders
@@ -479,6 +503,8 @@ export class NodeMaterial extends PushMaterial {
 
         var engine = scene.getEngine();
 
+        this._prepareDefinesForAttributes(mesh, defines);
+
         // Check if blocks are ready
         if (this._sharedData.blockingBlocks.some((b) => !b.isReady(mesh, this, defines, useInstances))) {
             return false;
@@ -492,6 +518,15 @@ export class NodeMaterial extends PushMaterial {
         // Need to recompile?
         if (defines.isDirty) {
             defines.markAsProcessed();
+
+            // Repeatable content generators
+            this._vertexCompilationState.compilationString = this._vertexCompilationState._builtCompilationString;
+            this._fragmentCompilationState.compilationString = this._fragmentCompilationState._builtCompilationString;
+
+            this._sharedData.repeatableContentBlocks.forEach((b) => {
+                b.replaceRepeatableContent(this._vertexCompilationState, this._fragmentCompilationState, mesh, defines);
+            });
+
             // Uniforms
             let mergedUniforms = this._vertexCompilationState.uniforms;
 
@@ -535,7 +570,8 @@ export class NodeMaterial extends PushMaterial {
                 defines: join,
                 fallbacks: fallbacks,
                 onCompiled: this.onCompiled,
-                onError: this.onError
+                onError: this.onError,
+                indexParameters: { maxSimultaneousLights: this.maxSimultaneousLights, maxSimultaneousMorphTargets: defines.NUM_MORPH_INFLUENCERS }
             }, engine);
 
             if (effect) {

+ 11 - 0
src/Materials/Node/nodeMaterialBlock.ts

@@ -296,6 +296,17 @@ export class NodeMaterialBlock {
     }
 
     /**
+     * Function called when a block is declared as repeatable content generator
+     * @param vertexShaderState defines the current compilation state for the vertex shader
+     * @param fragmentShaderState defines the current compilation state for the fragment shader
+     * @param mesh defines the mesh to be rendered
+     * @param defines defines the material defines to update
+     */
+    public replaceRepeatableContent(vertexShaderState: NodeMaterialBuildState, fragmentShaderState: NodeMaterialBuildState, mesh: AbstractMesh, defines: NodeMaterialDefines) {
+        // Do nothing
+    }
+
+    /**
      * Checks if the block is ready
      * @param mesh defines the mesh to be rendered
      * @param nodeMaterial defines the node material requesting the update

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

@@ -24,6 +24,8 @@ export enum NodeMaterialBlockConnectionPointTypes {
     Texture3D = 512,
     /** Vector3 or Color3 */
     Vector3OrColor3 = Vector3 | Color3,
+    /** Vector3 or Vector4 */
+    Vector3OrVector4 = Vector3 | Vector4,
     /** Vector4 or Color4 */
     Vector4OrColor4 = Vector4 | Color4,
     /** Color3 or Color4 */

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

@@ -43,6 +43,10 @@ export class NodeMaterialBuildState {
     private _samplerDeclaration = "";
     private _varyingTransfer = "";
 
+    private _repeatableContentAnchorIndex = 0;
+    /** @hidden */
+    public _builtCompilationString = "";
+
     /**
      * Gets the emitted compilation strings
      */
@@ -85,12 +89,26 @@ export class NodeMaterialBuildState {
         if (this._attributeDeclaration && !isFragmentMode) {
             this.compilationString = `\r\n${emitComments ? "//Attributes\r\n" : ""}${this._attributeDeclaration}\r\n${this.compilationString}`;
         }
+
+        this._builtCompilationString = this.compilationString;
+    }
+
+    /** @hidden */
+    public get _repeatableContentAnchor(): string {
+        return `###___ANCHOR${this._repeatableContentAnchorIndex++}___###`;
     }
 
     /** @hidden */
     public _getFreeVariableName(prefix: string): string {
         if (this.sharedData.variableNames[prefix] === undefined) {
             this.sharedData.variableNames[prefix] = 0;
+
+            // Check reserved words
+            if (prefix === "output" || prefix === "texture") {
+                return prefix + this.sharedData.variableNames[prefix];
+            }
+
+            return prefix;
         } else {
             this.sharedData.variableNames[prefix]++;
         }
@@ -131,6 +149,7 @@ export class NodeMaterialBuildState {
             case NodeMaterialBlockConnectionPointTypes.Color4:
             case NodeMaterialBlockConnectionPointTypes.Vector4:
             case NodeMaterialBlockConnectionPointTypes.Vector4OrColor4:
+            case NodeMaterialBlockConnectionPointTypes.Vector3OrVector4:
                 return "vec4";
             case NodeMaterialBlockConnectionPointTypes.Matrix:
                 return "mat4";
@@ -144,20 +163,28 @@ export class NodeMaterialBuildState {
     }
 
     /** @hidden */
-    public _emitFunction(name: string, code: string) {
+    public _emitFunction(name: string, code: string, comments: string) {
         if (this.functions[name]) {
             return;
         }
 
+        if (this.sharedData.emitComments) {
+            code = comments + `\r\n` + code;
+        }
+
         this.functions[name] = code;
     }
 
     /** @hidden */
-    public _emitCodeFromInclude(includeName: string, options?: {
+    public _emitCodeFromInclude(includeName: string, comments: string, options?: {
         replaceStrings?: { search: RegExp, replace: string }[],
     }) {
         let code = Effect.IncludesShadersStore[includeName] + "\r\n";
 
+        if (this.sharedData.emitComments) {
+            code = comments + `\r\n` + code;
+        }
+
         if (!options) {
             return code;
         }
@@ -173,7 +200,8 @@ export class NodeMaterialBuildState {
     }
 
     /** @hidden */
-    public _emitFunctionFromInclude(includeName: string, options?: {
+    public _emitFunctionFromInclude(includeName: string, comments: string, options?: {
+        repeatKey?: string,
         removeAttributes?: boolean,
         removeUniforms?: boolean,
         removeVaryings?: boolean,
@@ -184,13 +212,27 @@ export class NodeMaterialBuildState {
             return;
         }
 
-        if (!options) {
-            this.functions[includeName] = `#include<${includeName}>\r\n`;
+        if (!options || (!options.removeAttributes && !options.removeUniforms && !options.removeVaryings && !options.removeIfDef && !options.replaceStrings)) {
+
+            if (options && options.repeatKey) {
+                this.functions[includeName] = `#include<${includeName}>[0..${options.repeatKey}]\r\n`;
+            } else {
+                this.functions[includeName] = `#include<${includeName}>\r\n`;
+            }
+
+            if (this.sharedData.emitComments) {
+                this.functions[includeName] = comments + `\r\n` + this.functions[includeName];
+            }
+
             return;
         }
 
         this.functions[includeName] = Effect.IncludesShadersStore[includeName];
 
+        if (this.sharedData.emitComments) {
+            this.functions[includeName] = comments + `\r\n` + this.functions[includeName];
+        }
+
         if (options.removeIfDef) {
             this.functions[includeName] = this.functions[includeName].replace(/^\s*?#ifdef.+$/gm, "");
             this.functions[includeName] = this.functions[includeName].replace(/^\s*?#endif.*$/gm, "");
@@ -285,12 +327,11 @@ export class NodeMaterialBuildState {
             return;
         }
 
-        if (!point.associatedVariableName) {
-            point.associatedVariableName = point.name;
-        }
-
         // Uniforms
         if (point.isUniform) {
+            if (!point.associatedVariableName) {
+                point.associatedVariableName = this._getFreeVariableName(point.name);
+            }
             if (this.uniforms.indexOf(point.associatedVariableName) !== -1) {
                 return;
             }
@@ -322,24 +363,27 @@ export class NodeMaterialBuildState {
             return;
         }
 
+        // Attribute
         if (point.isAttribute) {
+            point.associatedVariableName = point.name;
+
             if (this.target === NodeMaterialBlockTargets.Fragment) { // Attribute for fragment need to be carried over by varyings
                 this._vertexState._emitUniformOrAttributes(point);
-                if (point.associatedVariableName) {
-                    return;
-                }
-                point.associatedVariableName = this._getFreeVariableName(point.name);
-                this._emitVaryings(point, "", true);
-                this._vertexState._emitVaryings(point, "", true, true);
                 return;
             }
 
-            if (this.attributes.indexOf(point.name) !== -1) {
+            if (this.attributes.indexOf(point.associatedVariableName) !== -1) {
                 return;
             }
 
-            this.attributes.push(point.name);
-            this._attributeDeclaration += `attribute ${this._getGLType(point.type)} ${point.name};\r\n`;
+            this.attributes.push(point.associatedVariableName);
+            if (define) {
+                this._attributeDeclaration += this._emitDefine(define);
+            }
+            this._attributeDeclaration += `attribute ${this._getGLType(point.type)} ${point.associatedVariableName};\r\n`;
+            if (define) {
+                this._attributeDeclaration += `#endif\r\n`;
+            }
         }
     }
 }

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

@@ -36,6 +36,11 @@ export class NodeMaterialBuildStateSharedData {
     public blocksWithDefines = new Array<NodeMaterialBlock>();
 
     /**
+    * List of blocks that can provide a repeatable content
+    */
+    public repeatableContentBlocks = new Array<NodeMaterialBlock>();
+
+    /**
      * List of blocks that can block the isReady function for the material
      */
     public blockingBlocks = new Array<NodeMaterialBlock>();

+ 21 - 12
src/Materials/materialHelper.ts

@@ -188,6 +188,26 @@ export class MaterialHelper {
     }
 
     /**
+     * Prepares the defines for morph targets
+     * @param mesh The mesh containing the geometry data we will draw
+     * @param defines The defines to update
+     */
+    public static PrepareDefinesForMorphTargets(mesh: AbstractMesh, defines: any) {
+        var manager = (<Mesh>mesh).morphTargetManager;
+        if (manager) {
+            defines["MORPHTARGETS_TANGENT"] = manager.supportsTangents && defines["TANGENT"];
+            defines["MORPHTARGETS_NORMAL"] = manager.supportsNormals && defines["NORMAL"];
+            defines["MORPHTARGETS"] = (manager.numInfluencers > 0);
+            defines["NUM_MORPH_INFLUENCERS"] = manager.numInfluencers;
+        } else {
+            defines["MORPHTARGETS_TANGENT"] = false;
+            defines["MORPHTARGETS_NORMAL"] = false;
+            defines["MORPHTARGETS"] = false;
+            defines["NUM_MORPH_INFLUENCERS"] = 0;
+        }
+    }
+
+    /**
      * Prepares the defines used in the shader depending on the attributes data available in the mesh
      * @param mesh The mesh containing the geometry data we will draw
      * @param defines The defines to update
@@ -230,18 +250,7 @@ export class MaterialHelper {
         }
 
         if (useMorphTargets) {
-            var manager = (<Mesh>mesh).morphTargetManager;
-            if (manager) {
-                defines["MORPHTARGETS_TANGENT"] = manager.supportsTangents && defines["TANGENT"];
-                defines["MORPHTARGETS_NORMAL"] = manager.supportsNormals && defines["NORMAL"];
-                defines["MORPHTARGETS"] = (manager.numInfluencers > 0);
-                defines["NUM_MORPH_INFLUENCERS"] = manager.numInfluencers;
-            } else {
-                defines["MORPHTARGETS_TANGENT"] = false;
-                defines["MORPHTARGETS_NORMAL"] = false;
-                defines["MORPHTARGETS"] = false;
-                defines["NUM_MORPH_INFLUENCERS"] = 0;
-            }
+            this.PrepareDefinesForMorphTargets(mesh, defines);
         }
 
         return true;