فهرست منبع

init: minimalist new nodematerial system

sunag 4 سال پیش
والد
کامیت
f738e6a89f

+ 38 - 0
examples/jsm/renderers/nodes/core/InputNode.js

@@ -0,0 +1,38 @@
+import Node from './Node.js';
+
+class InputNode extends Node {
+
+	constructor( type ) {
+		
+		super( type );
+		
+		this.isInputNode = true;
+		
+		// force constant for now
+		this.constant = true;
+		
+	}
+	
+	generateConst( builder, output ) {
+		
+		console.warn("Abstract function");
+		
+	}
+	
+	generate( builder, output ) {
+		
+		if ( this.constant ) {
+		
+			return builder.format( this.generateConst( builder, output ), output );
+			
+		} else {
+			
+			builder.createUniformFromNode( node );
+			
+		}
+		
+	}
+	
+}
+
+export default InputNode;

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

@@ -0,0 +1,31 @@
+class Node {
+
+	constructor( type ) {
+		
+		this.type = type;
+		
+		this.isNode = true;
+		
+	}
+	
+	getType( builder ) {
+		
+		return this.type;
+		
+	}
+	
+	generate( builder, output ) {
+		
+		console.warn("Abstract function");
+		
+	}
+	
+	build( builder, output ) {
+		
+		return this.generate( builder, output );
+		
+	}
+	
+}
+
+export default Node;

+ 166 - 0
examples/jsm/renderers/nodes/core/NodeBuilder.js

@@ -0,0 +1,166 @@
+const VERSION = '1';
+
+class NodeBuilder {
+
+	constructor() {
+		
+		this.slots = { vertex: [], fragment: [] };
+		this.defines = { vertex: {}, fragment: {} };
+		
+		this.nodesData = new WeakMap();
+		
+		this.shader = undefined;
+		
+	}
+	
+	setMaterial( material ) {
+		
+		this.material = material;
+		
+	}
+	
+	addSlot( shader, slot ) {
+		
+		this.slots[ shader ].push( slot );
+		
+	}
+	
+	addDefine( shader, name, value ) {
+		
+		this.defines[ shader ][ name ] = value || '';
+		
+	}
+	
+	generateVec3( x, y, z ) {
+		
+		return `vec3( ${x}, ${y}, ${z} )`;
+		
+	}
+	
+	generateFloat( value ) {
+		
+		return value + ( value % 1 ? '' : '.0' );
+		
+	}
+	/*
+	createDataFromNode( node ) {
+		
+		return this.nodesData[ node ] = this.nodesData[ node ] || {};
+		
+	}
+	*/
+	createUniformFromNode( node ) {
+		
+		
+		
+	}
+	/*
+	analyzeNode( node ) {
+		
+		
+	}
+	*/
+	flowNode( node, output ) {
+		
+		let flowData = {};
+		flowData.result = node.build( this, output );
+		
+		return flowData;
+		
+	}
+	
+	buildDefines( shader ) {
+		
+		const defines = this.defines[ shader ];
+		
+		let code = '';
+		
+		for ( let name in defines ) {
+			
+			code += `#define NODE_${name} ${defines[name]}\n`;
+			
+		}
+		
+		return code;
+		
+	}
+	
+	build( shader ) {
+		
+		const slots = this.slots[ shader ];
+		
+		if ( slots.length ) {
+			
+			this.addDefine( shader, 'NODE', VERSION );
+			
+			for( let i = 0; i < slots.length; i++) {
+			
+				let slot = slots[i];
+				
+				let flowData = this.flowNode( slot.node );
+				
+				this.addDefine( shader, slot.name, flowData.result );
+				
+			}
+			
+		}
+		
+		let defines = this.buildDefines( shader );
+		
+		return {
+			defines
+		};
+		
+	}
+	
+	format( code, fromType, toType ) {
+
+		const typeToType = toType + ' <- ' + fromType;
+
+		switch ( typeToType ) {
+
+			case 'f <- v2' : return code + '.x';
+			case 'f <- v3' : return code + '.x';
+			case 'f <- v4' : return code + '.x';
+			case 'f <- i' :
+			case 'f <- b' :	return 'float( ' + code + ' )';
+
+			case 'v2 <- f' : return 'vec2( ' + code + ' )';
+			case 'v2 <- v3': return code + '.xy';
+			case 'v2 <- v4': return code + '.xy';
+			case 'v2 <- i' :
+			case 'v2 <- b' : return 'vec2( float( ' + code + ' ) )';
+
+			case 'v3 <- f' : return 'vec3( ' + code + ' )';
+			case 'v3 <- v2': return 'vec3( ' + code + ', 0.0 )';
+			case 'v3 <- v4': return code + '.xyz';
+			case 'v3 <- i' :
+			case 'v3 <- b' : return 'vec2( float( ' + code + ' ) )';
+
+			case 'v4 <- f' : return 'vec4( ' + code + ' )';
+			case 'v4 <- v2': return 'vec4( ' + code + ', 0.0, 1.0 )';
+			case 'v4 <- v3': return 'vec4( ' + code + ', 1.0 )';
+			case 'v4 <- i' :
+			case 'v4 <- b' : return 'vec4( float( ' + code + ' ) )';
+
+			case 'i <- f' :
+			case 'i <- b' : return 'int( ' + code + ' )';
+			case 'i <- v2' : return 'int( ' + code + '.x )';
+			case 'i <- v3' : return 'int( ' + code + '.x )';
+			case 'i <- v4' : return 'int( ' + code + '.x )';
+
+			case 'b <- f' : return '( ' + code + ' != 0.0 )';
+			case 'b <- v2' : return '( ' + code + ' != vec2( 0.0 ) )';
+			case 'b <- v3' : return '( ' + code + ' != vec3( 0.0 ) )';
+			case 'b <- v4' : return '( ' + code + ' != vec4( 0.0 ) )';
+			case 'b <- i' : return '( ' + code + ' != 0 )';
+
+		}
+
+		return code;
+
+	}
+	
+}
+
+export default NodeBuilder;

+ 13 - 0
examples/jsm/renderers/nodes/core/NodeSlot.js

@@ -0,0 +1,13 @@
+class NodeSlot {
+
+	constructor( node, name, output ) {
+		
+		this.node = node;
+		this.name = name;
+		this.output = output;
+		
+	}
+	
+}
+
+export default NodeSlot;

+ 21 - 0
examples/jsm/renderers/nodes/inputs/Vector3Node.js

@@ -0,0 +1,21 @@
+import InputNode from '../core/InputNode.js';
+
+class Vector3Node extends InputNode {
+
+	constructor( value ) {
+
+		super( 'v3' );
+
+		this.value = value
+
+	}
+
+	generateConst( builder ) {
+
+		return builder.generateVec3( this.value.x, this.value.y, this.value.z );
+
+	}
+
+}
+
+export default Vector3Node;

+ 37 - 0
examples/jsm/renderers/nodes/math/OperatorNode.js

@@ -0,0 +1,37 @@
+import Node from '../core/Node.js';
+
+ class OperatorNode extends Node {
+
+	constructor( op, a, b ) {
+
+		super();
+
+		this.op = op;
+		
+		this.a = a;
+		this.b = b;
+		
+	}
+
+	getType( builder ) {
+		
+		// ignore auto length for now
+		
+		return this.a.getType( builder );
+		
+	}
+
+	generate( builder, output ) {
+
+		const nodeType = this.getType( builder );
+
+		const a = this.a.build( builder, nodeType );
+		const b = this.b.build( builder, nodeType );
+
+		return builder.format( '( ' + a + ' ' + this.op + ' ' + b + ' )', nodeType, output );
+
+	}
+		
+ }
+
+export default OperatorNode;

+ 13 - 45
examples/jsm/renderers/webgpu/WebGPUNodeBuilder.js

@@ -1,4 +1,5 @@
-import { NodeBuilder } from '../../nodes/core/NodeBuilder.js';
+import NodeSlot from '../nodes/core/NodeSlot.js';
+import NodeBuilder from '../nodes/core/NodeBuilder.js';
 
 class WebGPUNodeBuilder extends NodeBuilder {
 
@@ -8,30 +9,21 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 	}
 	
-	parseDefines( code, defines ) {
+	buildShader( shader, code ) {
 		
 		// use regex maybe for security?
-		let versionStrIndex = code.indexOf("\n");
+		const versionStrIndex = code.indexOf("\n");
 		
 		let shaderCode = code.substr( 0, versionStrIndex ) + "\n";
-		const names = Object.keys( defines );
-		
-		if (names.length) {
-
-			shaderCode += "\n#define NODE\n";
-
-			for ( let i = 0; i < names.length; i ++ ) {
-
-				let name = names[i];
-
-				shaderCode += `#define NODE_${name} ${defines[name]}\n`;
-
-			}
 
-		}
+		let shaderData = this.build( shader );
+		
+		shaderCode += shaderData.defines;
 
 		shaderCode += code.substr( versionStrIndex );
 
+		console.log( shaderCode );
+
 		return shaderCode;
 		
 	}
@@ -40,42 +32,18 @@ class WebGPUNodeBuilder extends NodeBuilder {
 		
 		const material = this.material;
 		
-		const nodesSlots = [];
-		const defines = [];
-		
-		let i, slot;
-		
 		if ( material.isMeshBasicMaterial ) {
 			
 			if ( material.color.isNode ) {
 				
-				slot = { name: 'COLOR', node: material.color, output: 'v3' };
-				
-				nodesSlots.push( slot );
+				this.addSlot( 'fragment', new NodeSlot( material.color, 'COLOR', 'v3' ) );
 				
 			}
 			
 		}
-		
-		for( i = 0; i < nodesSlots.length; i++) {
-			
-			nodesSlots[i].node.analyze( this );
-			
-		}
-		
-		for( i = 0; i < nodesSlots.length; i++) {
-			
-			slot = nodesSlots[i];
-			
-			let flowData = slot.node.flow( this, slot.output );
-			
-			defines[slot.name] = flowData.result;
-			defines[slot.name + '_CODE'] = flowData.code || '';
-			
-		}
-		
-		vertexShader = this.parseDefines( vertexShader, defines );
-		fragmentShader = this.parseDefines( fragmentShader, defines );
+
+		vertexShader = this.buildShader( 'vertex', vertexShader );
+		fragmentShader = this.buildShader( 'fragment', fragmentShader );
 
 		return {
 			vertexShader,

+ 1 - 1
examples/jsm/renderers/webgpu/WebGPURenderPipelines.js

@@ -827,7 +827,7 @@ const ShaderLib = {
 			outColor = texture( sampler2D( myTexture, mySampler ), vUv );
 
 			#ifdef NODE_COLOR
-				NODE_COLOR_CODE
+				/* NODE_COLOR_CODE ignore (node code group) for now */
 				outColor.rgb = NODE_COLOR;
 			#endif
 

+ 3 - 2
examples/webgpu_sandbox_nodes.html

@@ -19,7 +19,8 @@
 			import WebGPURenderer from './jsm/renderers/webgpu/WebGPURenderer.js';
 			import WebGPU from './jsm/renderers/webgpu/WebGPU.js';
 
-			import * as Nodes from './jsm/nodes/Nodes.js';
+			import Vector3Node from './jsm/renderers/nodes/inputs/Vector3Node.js';
+			import OperatorNode from './jsm/renderers/nodes/math/OperatorNode.js';
 
 			let camera, scene, renderer;
 
@@ -51,7 +52,7 @@
 				const geometryBox = new THREE.BoxBufferGeometry();
 				const materialBox = new THREE.MeshBasicMaterial( { map: texture } );
 
-				materialBox.color = new Nodes.ColorNode( 0x0099FF ).setReadonly( true );
+				materialBox.color = new OperatorNode( '+', new Vector3Node( new THREE.Vector3( 0, .6, 0 ) ), new Vector3Node( new THREE.Vector3( 0, 0, 1 ) ) );
 
 				box = new THREE.Mesh( geometryBox, materialBox );
 				box.position.set( 0, 1, 0 );