Browse Source

Node: Static and dynamic output type for extended nodes (#22590)

* Node: Generate once support

* cleanup
sunag 3 năm trước cách đây
mục cha
commit
92d826485a
29 tập tin đã thay đổi với 200 bổ sung337 xóa
  1. 7 25
      examples/jsm/renderers/nodes/accessors/CameraNode.js
  2. 2 4
      examples/jsm/renderers/nodes/accessors/ModelViewProjectionNode.js
  3. 10 42
      examples/jsm/renderers/nodes/accessors/NormalNode.js
  4. 9 33
      examples/jsm/renderers/nodes/accessors/Object3DNode.js
  5. 2 5
      examples/jsm/renderers/nodes/accessors/PointUVNode.js
  6. 15 58
      examples/jsm/renderers/nodes/accessors/PositionNode.js
  7. 2 2
      examples/jsm/renderers/nodes/accessors/ReferenceNode.js
  8. 5 18
      examples/jsm/renderers/nodes/core/AttributeNode.js
  9. 2 4
      examples/jsm/renderers/nodes/core/CodeNode.js
  10. 3 4
      examples/jsm/renderers/nodes/core/ConstNode.js
  11. 4 7
      examples/jsm/renderers/nodes/core/ExpressionNode.js
  12. 2 5
      examples/jsm/renderers/nodes/core/FunctionCallNode.js
  13. 21 0
      examples/jsm/renderers/nodes/core/Node.js
  14. 3 7
      examples/jsm/renderers/nodes/core/PropertyNode.js
  15. 2 2
      examples/jsm/renderers/nodes/core/StructVarNode.js
  16. 13 3
      examples/jsm/renderers/nodes/core/TempNode.js
  17. 2 2
      examples/jsm/renderers/nodes/core/VarNode.js
  18. 2 2
      examples/jsm/renderers/nodes/core/VaryNode.js
  19. 10 18
      examples/jsm/renderers/nodes/display/ColorSpaceNode.js
  20. 11 22
      examples/jsm/renderers/nodes/display/NormalMapNode.js
  21. 3 5
      examples/jsm/renderers/nodes/lights/LightContextNode.js
  22. 4 2
      examples/jsm/renderers/nodes/lights/LightNode.js
  23. 2 2
      examples/jsm/renderers/nodes/lights/LightsNode.js
  24. 4 4
      examples/jsm/renderers/nodes/math/MathNode.js
  25. 3 3
      examples/jsm/renderers/nodes/math/OperatorNode.js
  26. 2 4
      examples/jsm/renderers/nodes/utils/JoinNode.js
  27. 17 5
      examples/jsm/renderers/nodes/utils/SplitNode.js
  28. 21 32
      examples/jsm/renderers/nodes/utils/SpriteSheetUVNode.js
  29. 17 17
      examples/jsm/renderers/webgpu/nodes/WebGPUNodeBuilder.js

+ 7 - 25
examples/jsm/renderers/nodes/accessors/CameraNode.js

@@ -9,6 +9,8 @@ class CameraNode extends Object3DNode {
 
 		super( scope );
 
+		this._inputNode = null;
+
 	}
 
 	getNodeType( builder ) {
@@ -47,37 +49,17 @@ class CameraNode extends Object3DNode {
 
 	}
 
-	generate( builder, output ) {
-
-		const nodeData = builder.getDataFromNode( this );
-
-		let inputNode = this._inputNode;
-
-		if ( nodeData.inputNode === undefined ) {
-
-			const scope = this.scope;
-
-			if ( scope === CameraNode.PROJECTION_MATRIX ) {
-
-				if ( inputNode === null || inputNode.isMatrix4Node !== true ) {
+	generate( builder ) {
 
-					inputNode = new Matrix4Node( null );
-
-				}
-
-			} else {
-
-				return super.generate( builder, output );
-
-			}
+		const scope = this.scope;
 
-			this._inputNode = inputNode;
+		if ( scope === CameraNode.PROJECTION_MATRIX ) {
 
-			nodeData.inputNode = inputNode;
+			this._inputNode = new Matrix4Node( null );
 
 		}
 
-		return inputNode.build( builder, output );
+		return super.generate( builder );
 
 	}
 

+ 2 - 4
examples/jsm/renderers/nodes/accessors/ModelViewProjectionNode.js

@@ -16,14 +16,12 @@ class ModelViewProjectionNode extends Node {
 
 	}
 
-	generate( builder, output ) {
-
-		const type = this.getNodeType( builder );
+	generate( builder ) {
 
 		const mvpSnipped = this._mvpMatrix.build( builder );
 		const positionSnipped = this.position.build( builder, 'vec3' );
 
-		return builder.format( `( ${mvpSnipped} * vec4( ${positionSnipped}, 1.0 ) )`, type, output );
+		return `( ${mvpSnipped} * vec4( ${positionSnipped}, 1.0 ) )`;
 
 	}
 

+ 10 - 42
examples/jsm/renderers/nodes/accessors/NormalNode.js

@@ -21,61 +21,29 @@ class NormalNode extends Node {
 
 	}
 
-	generate( builder, output ) {
+	generate( builder ) {
 
-		const type = this.getNodeType( builder );
-		const nodeData = builder.getDataFromNode( this, builder.shaderStage );
 		const scope = this.scope;
 
-		let localNormalNode = nodeData.localNormalNode;
+		let outputNode = null;
 
-		if ( localNormalNode === undefined ) {
+		if ( scope === NormalNode.LOCAL ) {
 
-			localNormalNode = new AttributeNode( 'normal', 'vec3' );
+			outputNode = new AttributeNode( 'normal', 'vec3' );
 
-			nodeData.localNormalNode = localNormalNode;
+		} else if ( scope === NormalNode.VIEW ) {
 
-		}
-
-		let outputNode = localNormalNode;
-
-		if ( scope === NormalNode.VIEW ) {
-
-			let viewNormalNode = nodeData.viewNormalNode;
-
-			if ( viewNormalNode === undefined ) {
-
-				const vertexNormalNode = new OperatorNode( '*', new ModelNode( ModelNode.NORMAL_MATRIX ), localNormalNode );
-
-				viewNormalNode = new MathNode( MathNode.NORMALIZE, new VaryNode( vertexNormalNode ) );
-
-				nodeData.viewNormalNode = viewNormalNode;
-
-			}
-
-			outputNode = viewNormalNode;
+			const vertexNormalNode = new OperatorNode( '*', new ModelNode( ModelNode.NORMAL_MATRIX ), new NormalNode( NormalNode.LOCAL ) );
+			outputNode = new MathNode( MathNode.NORMALIZE, new VaryNode( vertexNormalNode ) );
 
 		} else if ( scope === NormalNode.WORLD ) {
 
-			let worldNormalNode = nodeData.worldNormalNode;
-
-			if ( worldNormalNode === undefined ) {
-
-				const vertexNormalNode = inverseTransformDirection.call( { dir: new NormalNode( NormalNode.VIEW ), matrix: new CameraNode( CameraNode.VIEW_MATRIX ) } );
-
-				worldNormalNode = new MathNode( MathNode.NORMALIZE, new VaryNode( vertexNormalNode ) );
-
-				nodeData.worldNormalNode = worldNormalNode;
-
-			}
-
-			outputNode = worldNormalNode;
+			const vertexNormalNode = inverseTransformDirection.call( { dir: new NormalNode( NormalNode.VIEW ), matrix: new CameraNode( CameraNode.VIEW_MATRIX ) } );
+			outputNode = new MathNode( MathNode.NORMALIZE, new VaryNode( vertexNormalNode ) );
 
 		}
 
-		const normalSnipped = outputNode.build( builder, type );
-
-		return builder.format( normalSnipped, type, output );
+		return outputNode.build( builder );
 
 	}
 

+ 9 - 33
examples/jsm/renderers/nodes/accessors/Object3DNode.js

@@ -78,49 +78,25 @@ class Object3DNode extends Node {
 
 	}
 
-	generate( builder, output ) {
+	generate( builder ) {
 
-		const nodeData = builder.getDataFromNode( this );
-
-		let inputNode = this._inputNode;
-
-		if ( nodeData.inputNode === undefined ) {
-
-			const scope = this.scope;
-
-			if ( scope === Object3DNode.WORLD_MATRIX || scope === Object3DNode.VIEW_MATRIX ) {
-
-				if ( inputNode === null || inputNode.isMatrix4Node !== true ) {
-
-					inputNode = new Matrix4Node( /*null*/ );
-
-				}
-
-			} else if ( scope === Object3DNode.NORMAL_MATRIX ) {
-
-				if ( inputNode === null || inputNode.isMatrix3Node !== true ) {
-
-					inputNode = new Matrix3Node( /*null*/ );
-
-				}
-
-			} else if ( scope === Object3DNode.POSITION || scope === Object3DNode.VIEW_POSITION ) {
+		const scope = this.scope;
 
-				if ( inputNode === null || inputNode.isVector3Node !== true ) {
+		if ( scope === Object3DNode.WORLD_MATRIX || scope === Object3DNode.VIEW_MATRIX ) {
 
-					inputNode = new Vector3Node();
+			this._inputNode = new Matrix4Node( /*null*/ );
 
-				}
+		} else if ( scope === Object3DNode.NORMAL_MATRIX ) {
 
-			}
+			this._inputNode = new Matrix3Node( /*null*/ );
 
-			this._inputNode = inputNode;
+		} else if ( scope === Object3DNode.POSITION || scope === Object3DNode.VIEW_POSITION ) {
 
-			nodeData.inputNode = inputNode;
+			this._inputNode = new Vector3Node();
 
 		}
 
-		return inputNode.build( builder, output );
+		return this._inputNode.build( builder );
 
 	}
 

+ 2 - 5
examples/jsm/renderers/nodes/accessors/PointUVNode.js

@@ -10,12 +10,9 @@ class PointUVNode extends Node {
 
 	}
 
-	generate( builder, output ) {
+	generate( builder ) {
 
-		const type = this.getNodeType( builder );
-		const snippet = 'vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y )';
-
-		return builder.format( snippet, type, output );
+		return 'vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y )';
 
 	}
 

+ 15 - 58
examples/jsm/renderers/nodes/accessors/PositionNode.js

@@ -13,7 +13,7 @@ class PositionNode extends Node {
 	static VIEW = 'view';
 	static VIEW_DIRECTION = 'viewDirection';
 
-	constructor( scope = PositionNode.POSITION ) {
+	constructor( scope = PositionNode.LOCAL ) {
 
 		super( 'vec3' );
 
@@ -21,77 +21,34 @@ class PositionNode extends Node {
 
 	}
 
-	generate( builder, output ) {
+	generate( builder ) {
 
-		const type = this.getNodeType( builder );
-		const nodeData = builder.getDataFromNode( this );
 		const scope = this.scope;
 
-		let localPositionNode = nodeData.localPositionNode;
+		let outputNode = null;
 
-		if ( localPositionNode === undefined ) {
+		if ( scope === PositionNode.LOCAL ) {
+			
+			outputNode = new AttributeNode( 'position', 'vec3' );
+			
+		} else if ( scope === PositionNode.WORLD ) {
 
-			localPositionNode = new AttributeNode( 'position', 'vec3' );
-
-			nodeData.localPositionNode = localPositionNode;
-
-		}
-
-		let outputNode = localPositionNode;
-
-		if ( scope === PositionNode.WORLD ) {
-
-			let worldPositionNode = nodeData.worldPositionNode;
-
-			if ( worldPositionNode === undefined ) {
-
-				const vertexPositionNode = transformDirection.call( { dir: localPositionNode, matrix: new ModelNode( ModelNode.WORLD_MATRIX ) } );
-
-				worldPositionNode = new VaryNode( vertexPositionNode );
-
-				nodeData.worldPositionNode = worldPositionNode;
-
-			}
-
-			outputNode = worldPositionNode;
+			const vertexPositionNode = transformDirection.call( { dir: new PositionNode( PositionNode.LOCAL ), matrix: new ModelNode( ModelNode.WORLD_MATRIX ) } );
+			outputNode = new VaryNode( vertexPositionNode );
 
 		} else if ( scope === PositionNode.VIEW ) {
 
-			let viewPositionNode = nodeData.viewPositionNode;
-
-			if ( viewPositionNode === undefined ) {
-
-				const vertexPositionNode = new OperatorNode( '*', new ModelNode( ModelNode.VIEW_MATRIX ), localPositionNode );
-
-				viewPositionNode = new VaryNode( vertexPositionNode );
-
-				nodeData.viewPositionNode = viewPositionNode;
-
-			}
-
-			outputNode = viewPositionNode;
+			const vertexPositionNode = new OperatorNode( '*', new ModelNode( ModelNode.VIEW_MATRIX ), new PositionNode( PositionNode.LOCAL ) );
+			outputNode = new VaryNode( vertexPositionNode );
 
 		} else if ( scope === PositionNode.VIEW_DIRECTION ) {
 
-			let viewDirPositionNode = nodeData.viewDirPositionNode;
-
-			if ( viewDirPositionNode === undefined ) {
-
-				const vertexPositionNode = new MathNode( MathNode.NEGATE, new PositionNode( PositionNode.VIEW ) );
-
-				viewDirPositionNode = new MathNode( MathNode.NORMALIZE, new VaryNode( vertexPositionNode ) );
-
-				nodeData.viewDirPositionNode = viewDirPositionNode;
-
-			}
-
-			outputNode = viewDirPositionNode;
+			const vertexPositionNode = new MathNode( MathNode.NEGATE, new PositionNode( PositionNode.VIEW ) );
+			outputNode = new MathNode( MathNode.NORMALIZE, new VaryNode( vertexPositionNode ) );
 
 		}
 
-		const positionSnipped = outputNode.build( builder, type );
-
-		return builder.format( positionSnipped, type, output );
+		return outputNode.build( builder, this.getNodeType( builder ) );
 
 	}
 

+ 2 - 2
examples/jsm/renderers/nodes/accessors/ReferenceNode.js

@@ -80,9 +80,9 @@ class ReferenceNode extends Node {
 
 	}
 
-	generate( builder, output ) {
+	generate( builder ) {
 
-		return this.node.build( builder, output );
+		return this.node.build( builder, this.getNodeType( builder ) );
 
 	}
 

+ 5 - 18
examples/jsm/renderers/nodes/core/AttributeNode.js

@@ -25,32 +25,19 @@ class AttributeNode extends Node {
 
 	}
 
-	generate( builder, output ) {
+	generate( builder ) {
 
-		const attributeName = this.getAttributeName( builder );
-		const attributeType = this.getNodeType( builder );
-
-		const attribute = builder.getAttribute( attributeName, attributeType );
+		const attribute = builder.getAttribute( this.getAttributeName( builder ), this.getNodeType( builder ) );
 
 		if ( builder.isShaderStage( 'vertex' ) ) {
 
-			return builder.format( attribute.name, attribute.type, output );
+			return attribute.name;
 
 		} else {
 
-			const nodeData = builder.getDataFromNode( this, builder.shaderStage );
-
-			let nodeVary = nodeData.varyNode;
-
-			if ( nodeVary === undefined ) {
-
-				nodeVary = new VaryNode( this );
-
-				nodeData.nodeVary = nodeVary;
-
-			}
+			const nodeVary = new VaryNode( this );
 
-			return nodeVary.build( builder, output );
+			return nodeVary.build( builder, attribute.type );
 
 		}
 

+ 2 - 4
examples/jsm/renderers/nodes/core/CodeNode.js

@@ -30,7 +30,7 @@ class CodeNode extends Node {
 
 	}
 
-	generate( builder, output ) {
+	generate( builder ) {
 
 		if ( this.useKeywords === true ) {
 
@@ -66,9 +66,7 @@ class CodeNode extends Node {
 
 		}
 
-		const type = this.getNodeType( builder );
-		const nodeCode = builder.getCodeFromNode( this, type );
-
+		const nodeCode = builder.getCodeFromNode( this, this.getNodeType( builder ) );
 		nodeCode.code = this.code;
 
 		return nodeCode.code;

+ 3 - 4
examples/jsm/renderers/nodes/core/ConstNode.js

@@ -12,12 +12,11 @@ class ConstNode extends CodeNode {
 
 	}
 
-	generate( builder, output ) {
+	generate( builder ) {
 
 		const code = super.generate( builder );
 
-		const type = this.getNodeType( builder );
-		const nodeCode = builder.getCodeFromNode( this, type );
+		const nodeCode = builder.getCodeFromNode( this, this.getNodeType( builder ) );
 
 		if ( this.name !== '' ) {
 
@@ -31,7 +30,7 @@ class ConstNode extends CodeNode {
 
 		nodeCode.code = `#define ${propertyName} ${code}`;
 
-		return builder.format( propertyName, type, output );
+		return propertyName;
 
 	}
 

+ 4 - 7
examples/jsm/renderers/nodes/core/ExpressionNode.js

@@ -1,6 +1,6 @@
-import Node from './Node.js';
+import TempNode from './TempNode.js';
 
-class ExpressionNode extends Node {
+class ExpressionNode extends TempNode {
 
 	constructor( snipped = '', nodeType = null ) {
 
@@ -10,12 +10,9 @@ class ExpressionNode extends Node {
 
 	}
 
-	generate( builder, output ) {
+	generate( builder ) {
 
-		const type = this.getNodeType( builder );
-		const snipped = this.snipped;
-
-		return builder.format( `( ${ snipped } )`, type, output );
+		return `( ${ this.snipped } )`;
 
 	}
 

+ 2 - 5
examples/jsm/renderers/nodes/core/FunctionCallNode.js

@@ -31,7 +31,7 @@ class FunctionCallNode extends TempNode {
 
 	}
 
-	generate( builder, output ) {
+	generate( builder ) {
 
 		const params = [];
 
@@ -56,12 +56,9 @@ class FunctionCallNode extends TempNode {
 
 		}
 
-		const type = this.getNodeType( builder );
 		const functionName = functionNode.build( builder, 'property' );
 
-		const callSnippet = `${functionName}( ${params.join( ', ' )} )`;
-
-		return builder.format( callSnippet, type, output );
+		return `${functionName}( ${params.join( ', ' )} )`;
 
 	}
 

+ 21 - 0
examples/jsm/renderers/nodes/core/Node.js

@@ -50,6 +50,27 @@ class Node {
 
 		builder.addNode( this );
 
+		const isGenerateOnce = this.generate.length === 1;
+
+		if ( isGenerateOnce ) {
+
+			const type = this.getNodeType( builder );
+			const nodeData = builder.getDataFromNode( this );
+
+			let snippet = nodeData.snippet;
+
+			if ( snippet === undefined ) {
+
+				snippet = this.generate( builder );
+
+				nodeData.snippet = snippet;
+
+			}
+
+			return builder.format( snippet, type, output );
+
+		}
+
 		return this.generate( builder, output );
 
 	}

+ 3 - 7
examples/jsm/renderers/nodes/core/PropertyNode.js

@@ -10,16 +10,12 @@ class PropertyNode extends Node {
 
 	}
 
-	generate( builder, output ) {
+	generate( builder ) {
 
-		const type = this.getNodeType( builder );
-
-		const nodeVary = builder.getVarFromNode( this, type );
+		const nodeVary = builder.getVarFromNode( this, this.getNodeType( builder ) );
 		nodeVary.name = this.name;
 
-		const propertyName = builder.getPropertyName( nodeVary );
-
-		return builder.format( propertyName, type, output );
+		return builder.getPropertyName( nodeVary );
 
 	}
 

+ 2 - 2
examples/jsm/renderers/nodes/core/StructVarNode.js

@@ -20,7 +20,7 @@ class StructVarNode extends Node {
 
 	}
 
-	generate( builder, output ) {
+	generate( builder ) {
 
 		const type = this.getNodeType( builder );
 
@@ -66,7 +66,7 @@ class StructVarNode extends Node {
 
 		}
 
-		return builder.format( property, type, output );
+		return property;
 
 	}
 

+ 13 - 3
examples/jsm/renderers/nodes/core/TempNode.js

@@ -17,15 +17,25 @@ class TempNode extends Node {
 			const nodeVar = builder.getVarFromNode( this, type );
 			const propertyName = builder.getPropertyName( nodeVar );
 
-			const snippet = super.build( builder, type );
+			const nodeData = builder.getDataFromNode( this );
 
-			builder.addFlowCode( `${propertyName} = ${snippet}` );
+			let snippet = nodeData.snippet;
+
+			if ( snippet === undefined ) {
+
+				snippet = super.build( builder, type );
+
+				builder.addFlowCode( `${propertyName} = ${snippet}` );
+
+				nodeData.snippet = snippet;
+
+			}
 
 			return builder.format( propertyName, type, output );
 
 		} else {
 
-			return super.build( builder, type );
+			return super.build( builder, output );
 
 		}
 

+ 2 - 2
examples/jsm/renderers/nodes/core/VarNode.js

@@ -17,7 +17,7 @@ class VarNode extends Node {
 
 	}
 
-	generate( builder, output ) {
+	generate( builder ) {
 
 		const type = builder.getVectorType( this.getNodeType( builder ) );
 		const name = this.name;
@@ -37,7 +37,7 @@ class VarNode extends Node {
 
 		builder.addFlowCode( `${propertyName} = ${snippet}` );
 
-		return builder.format( propertyName, type, output );
+		return propertyName;
 
 	}
 

+ 2 - 2
examples/jsm/renderers/nodes/core/VaryNode.js

@@ -19,7 +19,7 @@ class VaryNode extends Node {
 
 	}
 
-	generate( builder, output ) {
+	generate( builder ) {
 
 		const type = this.getNodeType( builder );
 		const value = this.value;
@@ -30,7 +30,7 @@ class VaryNode extends Node {
 		// force nodeVary.snippet work in vertex stage
 		builder.flowNodeFromShaderStage( NodeShaderStage.Vertex, value, type, propertyName );
 
-		return builder.format( propertyName, type, output );
+		return propertyName;
 
 	}
 

+ 10 - 18
examples/jsm/renderers/nodes/display/ColorSpaceNode.js

@@ -85,35 +85,27 @@ class ColorSpaceNode extends TempNode {
 
 	}
 
-	generate( builder, output ) {
+	generate( builder ) {
+
+		const type = this.getNodeType( builder );
 
 		const method = this.method;
 		const input = this.input;
 
 		if ( method !== ColorSpaceNode.LINEAR_TO_LINEAR ) {
 
-			const nodeData = builder.getDataFromNode( this );
-
-			let encodingFunctionCallNode = nodeData.encodingFunctionCallNode;
-
-			if (encodingFunctionCallNode === undefined) {
-
-				const encodingFunctionNode = EncodingFunctions[ method ];
-
-				encodingFunctionCallNode = encodingFunctionNode.call( {
-					value: input,
-					factor: this.factor
-				} );
-
-				nodeData.encodingFunctionCallNode = encodingFunctionCallNode;
+			const encodingFunctionNode = EncodingFunctions[ method ];
 
-			}
+			const encodingFunctionCallNode = encodingFunctionNode.call( {
+				value: input,
+				factor: this.factor
+			} );
 
-			return encodingFunctionCallNode.build( builder, output );
+			return encodingFunctionCallNode.build( builder, type );
 
 		} else {
 
-			return input.build( builder, output );
+			return input.build( builder, type );
 
 		}
 

+ 11 - 22
examples/jsm/renderers/nodes/display/NormalMapNode.js

@@ -50,12 +50,11 @@ class NormalMapNode extends TempNode {
 
 	}
 
-	generate( builder, output ) {
+	generate( builder ) {
 
 		const type = this.getNodeType( builder );
-		const normalMapType = this.normalMapType;
 
-		const nodeData = builder.getDataFromNode( this );
+		const normalMapType = this.normalMapType;
 
 		const normalOP = new OperatorNode( '*', this.value, new FloatNode( 2.0 ).setConst( true ) );
 		const normalMap = new OperatorNode( '-', normalOP, new FloatNode( 1.0 ).setConst( true ) );
@@ -66,29 +65,19 @@ class NormalMapNode extends TempNode {
 
 			const normal = new MathNode( MathNode.NORMALIZE, vertexNormalNode );
 
-			return normal.build( builder, output );
+			return normal.build( builder, type );
 
 		} else if ( normalMapType === TangentSpaceNormalMap ) {
 
-			let perturbNormal2ArbCall = nodeData.perturbNormal2ArbCall;
-
-			if (perturbNormal2ArbCall === undefined) {
-
-				perturbNormal2ArbCall = perturbNormal2Arb.call( {
-					eye_pos: new PositionNode( PositionNode.VIEW ),
-					surf_norm: new NormalNode( NormalNode.VIEW ),
-					mapN: normalMap,
-					faceDirection: new FloatNode( 1.0 ).setConst( true ),
-					uv: new UVNode()
-				} );
+			const perturbNormal2ArbCall = perturbNormal2Arb.call( {
+				eye_pos: new PositionNode( PositionNode.VIEW ),
+				surf_norm: new NormalNode( NormalNode.VIEW ),
+				mapN: normalMap,
+				faceDirection: new FloatNode( 1.0 ).setConst( true ),
+				uv: new UVNode()
+			} );
 
-				nodeData.perturbNormal2ArbCall = perturbNormal2ArbCall;
-
-			}
-
-			const snippet = perturbNormal2ArbCall.build( builder, output );
-			
-			return builder.format( snippet, type, output );
+			return perturbNormal2ArbCall.build( builder, type );
 			
 		}
 

+ 3 - 5
examples/jsm/renderers/nodes/lights/LightContextNode.js

@@ -15,7 +15,7 @@ class LightContextNode extends ContextNode {
 
 	}
 
-	generate( builder, output ) {
+	generate( builder ) {
 
 		const type = this.getNodeType( builder );
 
@@ -40,13 +40,11 @@ class LightContextNode extends ContextNode {
 
 		}
 
-		const totalLightSnippet = `( ${reflectedLight}.directDiffuse + ${reflectedLight}.directSpecular )`;
-
 		// add code
 
-		super.generate( builder, output );
+		super.generate( builder, type );
 
-		return builder.format( totalLightSnippet, type, output );
+		return `( ${reflectedLight}.directDiffuse + ${reflectedLight}.directSpecular )`;
 
 	}
 

+ 4 - 2
examples/jsm/renderers/nodes/lights/LightNode.js

@@ -52,7 +52,9 @@ class LightNode extends Node {
 
 	}
 
-	generate( builder, output ) {
+	generate( builder ) {
+
+		const type = this.getNodeType( builder );
 
 		this.lightPositionView.object3d = this.light;
 
@@ -72,7 +74,7 @@ class LightNode extends Node {
 
 		}
 
-		return this.color.build( builder, output );
+		return this.color.build( builder, type );
 
 	}
 

+ 2 - 2
examples/jsm/renderers/nodes/lights/LightsNode.js

@@ -11,7 +11,7 @@ class LightsNode extends Node {
 
 	}
 
-	generate( builder, output ) {
+	generate( builder ) {
 
 		const lightNodes = this.lightNodes;
 
@@ -21,7 +21,7 @@ class LightsNode extends Node {
 
 		}
 
-		return builder.format( 'vec3( 0.0 )', this.getNodeType( builder ), output );
+		return 'vec3( 0.0 )';
 
 	}
 

+ 4 - 4
examples/jsm/renderers/nodes/math/MathNode.js

@@ -105,7 +105,7 @@ class MathNode extends TempNode {
 
 	}
 
-	generate( builder, output ) {
+	generate( builder ) {
 
 		const method = this.method;
 
@@ -114,11 +114,11 @@ class MathNode extends TempNode {
 
 		if ( method === MathNode.NEGATE ) {
 
-			return builder.format( '( -' + this.a.build( builder, inputType ) + ' )', type, output );
+			return '( -' + this.a.build( builder, inputType ) + ' )';
 
 		} else if ( method === MathNode.INVERT ) {
 
-			return builder.format( '( 1.0 - ' + this.a.build( builder, inputType ) + ' )', type, output );
+			return '( 1.0 - ' + this.a.build( builder, inputType ) + ' )';
 
 		} else {
 
@@ -177,7 +177,7 @@ class MathNode extends TempNode {
 
 			}
 
-			return builder.format( `${method}( ${params.join(', ')} )`, type, output );
+			return `${method}( ${params.join(', ')} )`;
 
 		}
 

+ 3 - 3
examples/jsm/renderers/nodes/math/OperatorNode.js

@@ -22,13 +22,13 @@ class OperatorNode extends TempNode {
 
 			// matrix x vector
 
-			return typeB;
+			return builder.getVectorFromMatrix( typeA );
 
 		} else if ( builder.isVector( typeA ) && builder.isMatrix( typeB ) ) {
 
 			// vector x matrix
 
-			return typeA;
+			return builder.getVectorFromMatrix( typeB );
 
 		} else if ( builder.getTypeLength( typeB ) > builder.getTypeLength( typeA ) ) {
 
@@ -72,7 +72,7 @@ class OperatorNode extends TempNode {
 		const a = this.a.build( builder, typeA );
 		const b = this.b.build( builder, typeB );
 
-		return builder.format( `( ${a} ${this.op} ${b} )`, type, output );
+		return `( ${a} ${this.op} ${b} )`;
 
 	}
 

+ 2 - 4
examples/jsm/renderers/nodes/utils/JoinNode.js

@@ -16,7 +16,7 @@ class JoinNode extends Node {
 
 	}
 
-	generate( builder, output ) {
+	generate( builder ) {
 
 		const type = this.getNodeType( builder );
 		const values = this.values;
@@ -33,9 +33,7 @@ class JoinNode extends Node {
 
 		}
 
-		const snippet = `${type}( ${ snippetValues.join( ', ' ) } )`;
-
-		return builder.format( snippet, type, output );
+		return `${type}( ${ snippetValues.join( ', ' ) } )`;
 
 	}
 

+ 17 - 5
examples/jsm/renderers/nodes/utils/SplitNode.js

@@ -17,14 +17,26 @@ class SplitNode extends Node {
 
 	}
 
-	generate( builder, output ) {
+	generate( builder ) {
 
-		const type = this.node.getNodeType( builder );
-		const nodeSnippet = this.node.build( builder, type );
+		const node = this.node;
+		const nodeTypeLength = builder.getTypeLength( node.getNodeType( builder ) );
 
-		const snippet = `${nodeSnippet}.${this.components}`;
+		const components = this.components;
 
-		return builder.format( snippet, this.getNodeType( builder ), output );
+		let type = null;
+
+		if ( components.length >= nodeTypeLength ) {
+
+			// need expand the input node
+
+			type = this.getNodeType( builder );
+
+		}
+
+		const nodeSnippet = node.build( builder, type );
+
+		return `${nodeSnippet}.${this.components}`;
 
 	}
 

+ 21 - 32
examples/jsm/renderers/nodes/utils/SpriteSheetUVNode.js

@@ -18,49 +18,38 @@ class SpriteSheetUVNode extends Node {
 
 	}
 
-	generate( builder, output ) {
+	generate( builder ) {
 
-		const nodeData = builder.getDataFromNode( this );
+		const uv = this.uv;
+		const count = this.count;
+		const frame = this.frame;
 
-		let uvFrame = nodeData.uvFrame;
+		const one = new FloatNode( 1 ).setConst( true );
 
-		if ( nodeData.uvFrame === undefined ) {
+		const width = new SplitNode( count, 'x' );
+		const height = new SplitNode( count, 'y' );
 
-			const uv = this.uv;
-			const count = this.count;
-			const frame = this.frame;
+		const total = new OperatorNode( '*', width, height );
 
-			const one = new FloatNode( 1 ).setConst( true );
+		const roundFrame = new MathNode( MathNode.FLOOR, new MathNode( MathNode.MOD, frame, total ) );
 
-			const width = new SplitNode( count, 'x' );
-			const height = new SplitNode( count, 'y' );
+		const frameNum = new OperatorNode( '+', roundFrame, one );
 
-			const total = new OperatorNode( '*', width, height );
+		const cell = new MathNode( MathNode.MOD, roundFrame, width );
+		const row = new MathNode( MathNode.CEIL, new OperatorNode( '/', frameNum, width ) );
+		const rowInv = new OperatorNode( '-', height, row );
 
-			const roundFrame = new MathNode( MathNode.FLOOR, new MathNode( MathNode.MOD, frame, total ) );
+		const scale = new OperatorNode( '/', one, count );
 
-			const frameNum = new OperatorNode( '+', roundFrame, one );
+		const uvFrameOffset = new JoinNode( [
+			new OperatorNode( '*', cell, new SplitNode( scale, 'x' ) ),
+			new OperatorNode( '*', rowInv, new SplitNode( scale, 'y' ) )
+		] );
 
-			const cell = new MathNode( MathNode.MOD, roundFrame, width );
-			const row = new MathNode( MathNode.CEIL, new OperatorNode( '/', frameNum, width ) );
-			const rowInv = new OperatorNode( '-', height, row );
+		const uvScale = new OperatorNode( '*', uv, scale );
+		const uvFrame = new OperatorNode( '+', uvScale, uvFrameOffset );
 
-			const scale = new OperatorNode( '/', one, count );
-
-			const uvFrameOffset = new JoinNode( [
-				new OperatorNode( '*', cell, new SplitNode( scale, 'x' ) ),
-				new OperatorNode( '*', rowInv, new SplitNode( scale, 'y' ) )
-			] );
-
-			const uvScale = new OperatorNode( '*', uv, scale );
-
-			uvFrame = new OperatorNode( '+', uvScale, uvFrameOffset );
-
-			nodeData.uvFrame = uvFrame;
-
-		}
-
-		return uvFrame.build( builder, output );
+		return uvFrame.build( builder, this.getNodeType( builder ) );
 
 	}
 

+ 17 - 17
examples/jsm/renderers/webgpu/nodes/WebGPUNodeBuilder.js

@@ -393,21 +393,6 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 	}
 
-	composeShaderCode( code, snippet ) {
-
-		// use regex maybe for security?
-		const versionStrIndex = code.indexOf( '\n' );
-
-		let finalCode = code.substr( 0, versionStrIndex ) + '\n\n';
-
-		finalCode += snippet;
-
-		finalCode += code.substr( versionStrIndex );
-
-		return finalCode;
-
-	}
-
 	build() {
 
 		const keywords = this.getContextValue( 'keywords' );
@@ -422,13 +407,28 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 		super.build();
 
-		this.vertexShader = this.composeShaderCode( this.nativeShader.vertexShader, this.vertexShader );
-		this.fragmentShader = this.composeShaderCode( this.nativeShader.fragmentShader, this.fragmentShader );
+		this.vertexShader = this._composeShaderCode( this.nativeShader.vertexShader, this.vertexShader );
+		this.fragmentShader = this._composeShaderCode( this.nativeShader.fragmentShader, this.fragmentShader );
 
 		return this;
 
 	}
 
+	_composeShaderCode( code, snippet ) {
+
+		// use regex maybe for security?
+		const versionStrIndex = code.indexOf( '\n' );
+
+		let finalCode = code.substr( 0, versionStrIndex ) + '\n\n';
+
+		finalCode += snippet;
+
+		finalCode += code.substr( versionStrIndex );
+
+		return finalCode;
+
+	}
+
 	_getNodeUniform( uniformNode, type ) {
 
 		if ( type === 'float' ) return new FloatNodeUniform( uniformNode );