浏览代码

added support for transform in texture block

David Catuhe 6 年之前
父节点
当前提交
3939850ff3

+ 0 - 10
src/Materials/Node/Blocks/Fragment/alphaTestBlock.ts

@@ -39,16 +39,6 @@ export class AlphaTestBlock extends NodeMaterialBlock {
         return this._inputs[0];
     }
 
-    /** @hidden */
-    public get _canAddAtVertexRoot(): boolean {
-        return false;
-    }
-
-    /** @hidden */
-    public get _canAddAtFragmentRoot(): boolean {
-        return false;
-    }
-
     protected _buildBlock(state: NodeMaterialBuildState) {
         super._buildBlock(state);
 

+ 1 - 11
src/Materials/Node/Blocks/Fragment/fragmentOutputBlock.ts

@@ -36,17 +36,7 @@ export class FragmentOutputBlock extends NodeMaterialBlock {
     public get color(): NodeMaterialConnectionPoint {
         return this._inputs[0];
     }
-
-    /** @hidden */
-    public get _canAddAtVertexRoot(): boolean {
-        return false;
-    }
-
-    /** @hidden */
-    public get _canAddAtFragmentRoot(): boolean {
-        return true;
-    }
-
+    
     protected _buildBlock(state: NodeMaterialBuildState) {
         super._buildBlock(state);
 

+ 12 - 0
src/Materials/Node/Blocks/Vertex/bonesBlock.ts

@@ -8,6 +8,8 @@ import { Mesh } from '../../../../Meshes/mesh';
 import { Effect, EffectFallbacks } from '../../../effect';
 import { MaterialHelper } from '../../../materialHelper';
 import { NodeMaterialConnectionPoint } from '../../nodeMaterialBlockConnectionPoint';
+import { NodeMaterial } from '../../nodeMaterial';
+import { MaterialDefines } from '../../../materialDefines';
 
 /**
  * Block used to add support for vertex skinning (bones)
@@ -100,6 +102,13 @@ export class BonesBlock extends NodeMaterialBlock {
         MaterialHelper.BindBonesParameters(mesh, effect);
     }
 
+    public prepareDefines(mesh: AbstractMesh, nodeMaterial: NodeMaterial, defines: MaterialDefines) {
+        if (!defines._areAttributesDirty) {
+            return;
+        }
+        MaterialHelper.PrepareDefinesForBones(mesh, defines);
+    }
+
     protected _buildBlock(state: NodeMaterialBuildState) {
         super._buildBlock(state);
 
@@ -109,6 +118,9 @@ export class BonesBlock extends NodeMaterialBlock {
         // Register for binding
         state.sharedData.bindableBlocks.push(this);
 
+        // Register for defines
+        state.sharedData.blocksWithDefines.push(this);
+
         // Register internal uniforms and samplers
         state.uniforms.push("boneTextureWidth");
         state.uniforms.push("mBones");

+ 0 - 10
src/Materials/Node/Blocks/Vertex/vertexOutputBlock.ts

@@ -34,16 +34,6 @@ export class VertexOutputBlock extends NodeMaterialBlock {
         return this._inputs[0];
     }
 
-    /** @hidden */
-    public get _canAddAtVertexRoot(): boolean {
-        return false;
-    }
-
-    /** @hidden */
-    public get _canAddAtFragmentRoot(): boolean {
-        return false;
-    }
-
     protected _buildBlock(state: NodeMaterialBuildState) {
         super._buildBlock(state);
 

+ 78 - 6
src/Materials/Node/Blocks/textureBlock.ts

@@ -3,22 +3,42 @@ import { NodeMaterialBlockConnectionPointTypes } from '../nodeMaterialBlockConne
 import { NodeMaterialBuildState } from '../nodeMaterialBuildState';
 import { NodeMaterialBlockTargets } from '../nodeMaterialBlockTargets';
 import { NodeMaterialConnectionPoint } from '../nodeMaterialBlockConnectionPoint';
+import { BaseTexture } from '../../Textures/baseTexture';
 
 /**
  * Block used to read a texture from a sampler
  */
 export class TextureBlock extends NodeMaterialBlock {
+
+    /**
+     * Gets or sets a boolean indicating that the block can automatically fetch the texture matrix
+     */
+    public autoConnectTextureMatrix = true;
+
+    /**
+     * Gets or sets a boolean indicating that the block can automatically select the uv channel based on texture
+     */
+    public autoSelectUV = true;
+
     /**
      * Create a new TextureBlock
      * @param name defines the block name
      */
     public constructor(name: string) {
-        super(name, NodeMaterialBlockTargets.Fragment);
+        super(name, NodeMaterialBlockTargets.VertexAndFragment);
 
         this.registerInput("uv", NodeMaterialBlockConnectionPointTypes.Vector2);
+        this.registerInput("textureInfo", NodeMaterialBlockConnectionPointTypes.Vector2, true);
+
+        this.registerInput("transformedUV", NodeMaterialBlockConnectionPointTypes.Vector2);
         this.registerInput("texture", NodeMaterialBlockConnectionPointTypes.Texture);
+        this.registerInput("textureTransform", NodeMaterialBlockConnectionPointTypes.Matrix, true);
 
         this.registerOutput("color", NodeMaterialBlockConnectionPointTypes.Color4);
+
+        // Auto configuration
+        this._inputs[0].setAsAttribute();
+        this._inputs[0].connectTo(this._inputs[2]);
     }
 
     /**
@@ -37,22 +57,74 @@ export class TextureBlock extends NodeMaterialBlock {
     }
 
     /**
+     * Gets the texture information input component
+     */
+    public get textureInfo(): NodeMaterialConnectionPoint {
+        return this._inputs[1];
+    }
+        
+    /**
+     * Gets the transformed uv input component
+     */
+    public get transformedUV(): NodeMaterialConnectionPoint {
+        return this._inputs[2];
+    }
+
+    /**
      * Gets the texture input component
      */
     public get texture(): NodeMaterialConnectionPoint {
-        return this._inputs[1];
-    }      
+        return this._inputs[3];
+    }     
+    
+    /**
+     * Gets the texture transform input component
+     */
+    public get textureTransform(): NodeMaterialConnectionPoint {
+        return this._inputs[4];
+    }    
+    
+    public initialize(state: NodeMaterialBuildState) {
+        if (this.texture.value && this.texture.value.getTextureMatrix) {
+            const texture = this.texture.value as BaseTexture;
+
+            if (this.autoConnectTextureMatrix) {
+                this.textureTransform.valueCallback = () => texture.getTextureMatrix();
+            }
+            if (this.autoSelectUV) {
+                this.uv.setAsAttribute("uv" + (texture.coordinatesIndex ? (texture.coordinatesIndex + 1) : ""));
+            }
+        }
+    }
 
     protected _buildBlock(state: NodeMaterialBuildState) {
         super._buildBlock(state);
 
         let uvInput = this.uv;
-        let samplerInput = this.texture;
+        let transformedUV = this.transformedUV;
+        let textureInfo = this.textureInfo;
+        let textureTransform = this.textureTransform;
+        let isTextureInfoConnected = textureInfo.connectedPoint != null || textureInfo.isUniform;        
+        let isTextureTransformConnected = textureTransform.connectedPoint != null || textureTransform.isUniform;
+
+        if (state.target === NodeMaterialBlockTargets.Fragment) { // Fragment
+            let samplerInput = this.texture;
+
+            let output = this._outputs[0];
 
-        let output = this._outputs[0];
+            const complement = isTextureInfoConnected ? ` * ${textureInfo.associatedVariableName}.y` : "";
 
-        state.compilationString += `vec4 ${output.associatedVariableName} = texture2D(${samplerInput.associatedVariableName}, ${uvInput.associatedVariableName});\r\n`;
+            state.compilationString += `vec4 ${output.associatedVariableName} = texture2D(${samplerInput.associatedVariableName}, ${transformedUV.associatedVariableName})${complement};\r\n`;
+        } else { // Vertex
+            transformedUV.associatedVariableName = state._getFreeVariableName(transformedUV.name);
+            state._emitVaryings(transformedUV, true);
 
+            if (isTextureTransformConnected) {
+                state.compilationString += `${transformedUV.associatedVariableName} =  vec2(${textureTransform.associatedVariableName} * vec4(${uvInput.associatedVariableName}, 1.0, 0.0));`;
+            } else {
+                state.compilationString += `${transformedUV.associatedVariableName} =  ${uvInput.associatedVariableName};`;
+            }
+        }
         return this;
     }
 }

+ 57 - 56
src/Materials/Node/nodeMaterial.ts

@@ -15,7 +15,6 @@ import { NodeMaterialBlockTargets } from './nodeMaterialBlockTargets';
 import { NodeMaterialBuildStateSharedData } from './NodeMaterialBuildStateSharedData';
 import { SubMesh } from '../../Meshes/subMesh';
 import { MaterialDefines } from '../../Materials/materialDefines';
-import { MaterialHelper } from '../../Materials/materialHelper';
 
 /** @hidden */
 export class NodeMaterialDefines extends MaterialDefines {
@@ -66,12 +65,12 @@ export class NodeMaterial extends PushMaterial {
     /**
      * Gets or sets the root nodes of the material vertex shader
      */
-    private _vertexRootNodes = new Array<NodeMaterialBlock>();
+    private _vertexOutputNodes = new Array<NodeMaterialBlock>();
 
     /**
      * Gets or sets the root nodes of the material fragment (pixel) shader
      */
-    private _fragmentRootNodes = new Array<NodeMaterialBlock>();
+    private _fragmentOutputNodes = new Array<NodeMaterialBlock>();
 
     /** Gets or sets options to control the node material overall behavior */
     public get options() {
@@ -106,21 +105,21 @@ export class NodeMaterial extends PushMaterial {
     }
 
     /**
-     * Add a new block to the list of root nodes
+     * Add a new block to the list of output nodes
      * @param node defines the node to add
      * @returns the current material
      */
-    public addRootNode(node: NodeMaterialBlock) {
+    public addOutputNode(node: NodeMaterialBlock) {
         if (node.target === null) {
-            throw "This node is not meant to be at root level. You may want to explicitly set its target value.";
+            throw "This node is not meant to be an output node. You may want to explicitly set its target value.";
         }
 
-        if ((node.target & NodeMaterialBlockTargets.Vertex) !== 0 && node._canAddAtVertexRoot) {
-            this._addVertexRootNode(node);
+        if ((node.target & NodeMaterialBlockTargets.Vertex) !== 0) {
+            this._addVertexOutputNode(node);
         }
 
-        if ((node.target & NodeMaterialBlockTargets.Fragment) !== 0 && node._canAddAtFragmentRoot) {
-            this._addFragmentRootNode(node);
+        if ((node.target & NodeMaterialBlockTargets.Fragment) !== 0) {
+            this._addFragmentOutputNode(node);
         }
 
         return this;
@@ -131,62 +130,62 @@ export class NodeMaterial extends PushMaterial {
      * @param node defines the node to remove
      * @returns the current material
      */
-    public removeRootNode(node: NodeMaterialBlock) {
+    public removeOutputNode(node: NodeMaterialBlock) {
         if (node.target === null) {
             return this;
         }
 
         if ((node.target & NodeMaterialBlockTargets.Vertex) !== 0) {
-            this._removeVertexRootNode(node);
+            this._removeVertexOutputNode(node);
         }
 
         if ((node.target & NodeMaterialBlockTargets.Fragment) !== 0) {
-            this._removeFragmentRootNode(node);
+            this._removeFragmentOutputNode(node);
         }
 
         return this;
     }
 
-    private _addVertexRootNode(node: NodeMaterialBlock) {
-        if (this._vertexRootNodes.indexOf(node) !== -1) {
+    private _addVertexOutputNode(node: NodeMaterialBlock) {
+        if (this._vertexOutputNodes.indexOf(node) !== -1) {
             return;
         }
 
         node.target = NodeMaterialBlockTargets.Vertex;
-        this._vertexRootNodes.push(node);
+        this._vertexOutputNodes.push(node);
 
         return this;
     }
 
-    private _removeVertexRootNode(node: NodeMaterialBlock) {
-        let index = this._vertexRootNodes.indexOf(node);
+    private _removeVertexOutputNode(node: NodeMaterialBlock) {
+        let index = this._vertexOutputNodes.indexOf(node);
         if (index === -1) {
             return;
         }
 
-        this._vertexRootNodes.splice(index, 1);
+        this._vertexOutputNodes.splice(index, 1);
 
         return this;
     }
 
-    private _addFragmentRootNode(node: NodeMaterialBlock) {
-        if (this._fragmentRootNodes.indexOf(node) !== -1) {
+    private _addFragmentOutputNode(node: NodeMaterialBlock) {
+        if (this._fragmentOutputNodes.indexOf(node) !== -1) {
             return;
         }
 
         node.target = NodeMaterialBlockTargets.Fragment;
-        this._fragmentRootNodes.push(node);
+        this._fragmentOutputNodes.push(node);
 
         return this;
     }
 
-    private _removeFragmentRootNode(node: NodeMaterialBlock) {
-        let index = this._fragmentRootNodes.indexOf(node);
+    private _removeFragmentOutputNode(node: NodeMaterialBlock) {
+        let index = this._fragmentOutputNodes.indexOf(node);
         if (index === -1) {
             return;
         }
 
-        this._fragmentRootNodes.splice(index, 1);
+        this._fragmentOutputNodes.splice(index, 1);
 
         return this;
     }
@@ -207,14 +206,15 @@ export class NodeMaterial extends PushMaterial {
         return this._sharedData.hints.needAlphaTesting;
     }
 
-    private _propagateTarget(node: NodeMaterialBlock, target: NodeMaterialBlockTargets, state: NodeMaterialBuildState) {
-        node.target = target;
+    private _initializeBlock(node: NodeMaterialBlock, state: NodeMaterialBuildState) {
         node.initialize(state);
 
-        for (var exitPoint of node.outputs) {
-            for (var block of exitPoint.connectedBlocks) {
-                if (block) {
-                    this._propagateTarget(block, target, state);
+        for (var inputs of node.inputs) {
+            let connectedPoint = inputs.connectedPoint;
+            if (connectedPoint) {
+                let block = connectedPoint.ownerBlock;
+                if (block !== node) {
+                    this._initializeBlock(block, state);
                 }
             }
         }
@@ -225,9 +225,11 @@ export class NodeMaterial extends PushMaterial {
             node.buildId = id;
         }
 
-        for (var exitPoint of node.outputs) {
-            for (var block of exitPoint.connectedBlocks) {
-                if (block) {
+        for (var inputs of node.inputs) {
+            let connectedPoint = inputs.connectedPoint;
+            if (connectedPoint) {
+                let block = connectedPoint.ownerBlock;
+                if (block !== node) {
                     this._resetDualBlocks(block, id);
                 }
             }
@@ -240,12 +242,12 @@ export class NodeMaterial extends PushMaterial {
      */
     public build(verbose: boolean = false) {
         this._buildWasSuccessful = false;
-        if (this._vertexRootNodes.length === 0) {
-            throw "You must define at least one vertexRootNode";
+        if (this._vertexOutputNodes.length === 0) {
+            throw "You must define at least one vertexOutputNode";
         }
 
-        if (this._fragmentRootNodes.length === 0) {
-            throw "You must define at least one fragmentRootNode";
+        if (this._fragmentOutputNodes.length === 0) {
+            throw "You must define at least one fragmentOutputNode";
         }
 
         // Compilation state
@@ -262,29 +264,29 @@ export class NodeMaterial extends PushMaterial {
         this._sharedData.emitComments = this._options.emitComments;
         this._sharedData.verbose = verbose;
 
-        // Propagate targets
-        for (var vertexRootNode of this._vertexRootNodes) {
-            this._propagateTarget(vertexRootNode, NodeMaterialBlockTargets.Vertex, this._vertexCompilationState);
+        // Initialize blocks
+        for (var vertexOutputNode of this._vertexOutputNodes) {
+            this._initializeBlock(vertexOutputNode, this._vertexCompilationState);
         }
 
-        for (var fragmentRootNode of this._fragmentRootNodes) {
-            this._propagateTarget(fragmentRootNode, NodeMaterialBlockTargets.Fragment, this._fragmentCompilationState);
+        for (var fragmentOutputNode of this._fragmentOutputNodes) {
+            this._initializeBlock(fragmentOutputNode, this._fragmentCompilationState);
         }
 
         // Vertex
-        for (var vertexRootNode of this._vertexRootNodes) {
-            vertexRootNode.build(this._vertexCompilationState);
+        for (var vertexOutputNode of this._vertexOutputNodes) {
+            vertexOutputNode.build(this._vertexCompilationState);
         }
 
         // Fragment
         this._fragmentCompilationState._vertexState = this._vertexCompilationState;
 
-        for (var fragmentRootNode of this._fragmentRootNodes) {
-            this._resetDualBlocks(fragmentRootNode, this._buildId - 1);
+        for (var fragmentOutputNode of this._fragmentOutputNodes) {
+            this._resetDualBlocks(fragmentOutputNode, this._buildId - 1);
         }
 
-        for (var fragmentRootNode of this._fragmentRootNodes) {
-            fragmentRootNode.build(this._fragmentCompilationState);
+        for (var fragmentOutputNode of this._fragmentOutputNodes) {
+            fragmentOutputNode.build(this._fragmentCompilationState);
         }
 
         // Finalize
@@ -350,8 +352,7 @@ export class NodeMaterial extends PushMaterial {
             }
         }
 
-        // Shared defines
-        MaterialHelper.PrepareDefinesForAttributes(mesh, defines, false, true, false, false);
+        // Shared defines        
         this._sharedData.blocksWithDefines.forEach((b) => {
             b.prepareDefines(mesh, this, defines);
         });
@@ -476,15 +477,15 @@ export class NodeMaterial extends PushMaterial {
         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.bindableBlocks) {
                     block.bind(effect, mesh);
                 }
+
+                // Connection points
+                for (var connectionPoint of sharedData.uniformConnectionPoints) {
+                    connectionPoint.transmit(effect, scene);
+                }
             }
         }
 

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

@@ -268,16 +268,6 @@ export class NodeMaterialBlock {
         // Empty. Must be defined by child nodes
     }
 
-    /** @hidden */
-    public get _canAddAtVertexRoot(): boolean {
-        return true; // Must be overriden by children
-    }
-
-    /** @hidden */
-    public get _canAddAtFragmentRoot(): boolean {
-        return true; // Must be overriden by children
-    }
-
     /**
      * Add potential fallbacks if shader compilation fails
      * @param mesh defines the mesh to be rendered
@@ -321,7 +311,7 @@ export class NodeMaterialBlock {
             }
 
             let block = input.connectedPoint.ownerBlock;
-            if (block && block.target === this.target && block.buildId !== state.sharedData.buildId) {
+            if (block && block !== this && block.buildId !== state.sharedData.buildId) {
                 block.build(state);
             }
         }
@@ -335,6 +325,16 @@ export class NodeMaterialBlock {
             console.log(`${state.target === NodeMaterialBlockTargets.Vertex ? "Vertex shader" : "Fragment shader"}: Building ${this.name} [${this.getClassName()}]`);
         }
 
+
+        /** Prepare outputs */
+        for (var output of this._outputs) {
+            if ((output.target & this.target!) === 0) {//} || output.associatedVariableName) {
+                continue;
+            }
+            output.associatedVariableName = state._getFreeVariableName(output.name);
+            state._emitVaryings(output);
+        }
+        
         // Build
         for (var input of this._inputs) {
             if ((input.target & this.target!) === 0) {
@@ -355,15 +355,6 @@ export class NodeMaterialBlock {
             }
         }
 
-        /** Prepare outputs */
-        for (var output of this._outputs) {
-            if ((output.target & this.target!) === 0 || output.associatedVariableName) {
-                continue;
-            }
-            output.associatedVariableName = state._getFreeVariableName(output.name);
-            state._emitVaryings(output);
-        }
-
         if (state.sharedData.emitComments) {
             state.compilationString += `\r\n//${this.name}\r\n`;
         }

+ 3 - 1
src/Materials/Node/nodeMaterialBlockConnectionPoint.ts

@@ -318,10 +318,11 @@ export class NodeMaterialConnectionPoint {
             case NodeMaterialBlockConnectionPointTypes.Int:
                 effect.setInt(this.name, value);
                 break;
+            case NodeMaterialBlockConnectionPointTypes.Color3OrColor4:
             case NodeMaterialBlockConnectionPointTypes.Color3:
                 effect.setColor3(this.name, value);
                 break;
-            case NodeMaterialBlockConnectionPointTypes.Color4:
+                case NodeMaterialBlockConnectionPointTypes.Color4:
                 effect.setDirectColor4(this.name, value);
                 break;
             case NodeMaterialBlockConnectionPointTypes.Vector2:
@@ -330,6 +331,7 @@ export class NodeMaterialConnectionPoint {
             case NodeMaterialBlockConnectionPointTypes.Vector3:
                 effect.setVector3(this.name, value);
                 break;
+            case NodeMaterialBlockConnectionPointTypes.Vector4OrColor4:
             case NodeMaterialBlockConnectionPointTypes.Vector4:
                 effect.setVector4(this.name, value);
                 break;

+ 24 - 15
src/Materials/materialHelper.ts

@@ -165,6 +165,29 @@ export class MaterialHelper {
     }
 
     /**
+     * Prepares the defines for bones
+     * @param mesh The mesh containing the geometry data we will draw
+     * @param defines The defines to update
+     */
+    public static PrepareDefinesForBones(mesh: AbstractMesh, defines: any) {
+        if (mesh.useBones && mesh.computeBonesUsingShaders && mesh.skeleton) {
+            defines["NUM_BONE_INFLUENCERS"] = mesh.numBoneInfluencers;
+
+            const materialSupportsBoneTexture = defines["BONETEXTURE"] !== undefined;
+
+            if (mesh.skeleton.isUsingTextureForMatrices && materialSupportsBoneTexture) {
+                defines["BONETEXTURE"] = true;
+            } else {
+                defines["BonesPerMesh"] = (mesh.skeleton.bones.length + 1);
+                defines["BONETEXTURE"] = materialSupportsBoneTexture ? false : undefined;
+            }
+        } else {
+            defines["NUM_BONE_INFLUENCERS"] = 0;
+            defines["BonesPerMesh"] = 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
@@ -203,21 +226,7 @@ export class MaterialHelper {
         }
 
         if (useBones) {
-            if (mesh.useBones && mesh.computeBonesUsingShaders && mesh.skeleton) {
-                defines["NUM_BONE_INFLUENCERS"] = mesh.numBoneInfluencers;
-
-                const materialSupportsBoneTexture = defines["BONETEXTURE"] !== undefined;
-
-                if (mesh.skeleton.isUsingTextureForMatrices && materialSupportsBoneTexture) {
-                    defines["BONETEXTURE"] = true;
-                } else {
-                    defines["BonesPerMesh"] = (mesh.skeleton.bones.length + 1);
-                    defines["BONETEXTURE"] = materialSupportsBoneTexture ? false : undefined;
-                }
-            } else {
-                defines["NUM_BONE_INFLUENCERS"] = 0;
-                defines["BonesPerMesh"] = 0;
-            }
+            this.PrepareDefinesForBones(mesh, defines);
         }
 
         if (useMorphTargets) {