Pārlūkot izejas kodu

AttributeNode WIP

sunag 4 gadi atpakaļ
vecāks
revīzija
99e60add28

+ 21 - 4
examples/jsm/renderers/nodes/accessors/UVNode.js

@@ -1,6 +1,6 @@
-import Node from '../core/Node.js';
+import AttributeNode from '../core/AttributeNode.js';
 
-class UVNode extends Node {
+class UVNode extends AttributeNode {
 
 	constructor( index = 0 ) {
 
@@ -9,10 +9,27 @@ class UVNode extends Node {
 		this.index = index;
 
 	}
+	
+	getIndexProperty( prefix ) {
+		
+		return prefix + ( this.index > 0 ? this.index + 1 : '' );
+		
+	}
+	
+	getAttributeName( /*builder*/ ) {
+
+		return this.getIndexProperty( 'uv' );
 
-	generate( builder, output ) {
+	}
+	
+	getAttributeProperty( builder ) {
+		
+		// customize 'uv' property
+		const property = this.getIndexProperty( 'vUv' );
+		
+		this.setAttributeProperty( property );
 		
-		return builder.format( builder.getUV( this.index ), this.getType( builder ), output );
+		return super.getAttributeProperty( builder );
 		
 	}
 

+ 54 - 0
examples/jsm/renderers/nodes/core/AttributeNode.js

@@ -0,0 +1,54 @@
+import Node from './Node.js';
+
+class AttributeNode extends Node {
+
+	constructor( type, name = null, property = null ) {
+
+		super( type );
+
+		this.name = name;
+		this.property = property;
+
+	}
+	
+	setAttributeName( name ) {
+		
+		this.name = name;
+		
+		return this;
+		
+	}
+	
+	getAttributeName( /*builder*/ ) {
+		
+		return this.name;
+		
+	}
+	
+	setAttributeProperty( name ) {
+		
+		this.property = name;
+		
+		return this;
+		
+	}
+	
+	getAttributeProperty( builder ) {
+		
+		const attribute = builder.getAttribute( this.getType( builder ), this.getAttributeName( builder ), this.property );
+		
+		return attribute.property;
+		
+	}
+	
+	generate( builder, output ) {
+		
+		const attributeProperty = this.getAttributeProperty( builder );
+		
+		return builder.format( attributeProperty, this.getType( builder ), output );
+		
+	}
+
+}
+
+export default AttributeNode;

+ 69 - 30
examples/jsm/renderers/nodes/core/NodeBuilder.js

@@ -1,7 +1,5 @@
 import NodeUniform from './NodeUniform.js';
 
-const VERSION = '1';
-
 class NodeBuilder {
 
 	constructor( material, renderer ) {
@@ -14,6 +12,8 @@ class NodeBuilder {
 		this.slots = { vertex: [], fragment: [] };
 		this.defines = { vertex: {}, fragment: {} };
 		this.uniforms = { vertex: [], fragment: [] };
+		this.attributes = {};
+		this.attributeCount = 0;
 
 		this.nodesData = new WeakMap();
 
@@ -58,10 +58,32 @@ class NodeBuilder {
 		
 	}
 	
-	getUV( /*index*/ ) {
+	getAttribute( type, name, property = null ) {
+		
+		let attribute = this.attributes[ name ];
+		
+		if ( attribute === undefined ) {
+			
+			const index = this.attributeCount++;
+			
+			if ( property === null ) {
+				
+				property = `node_A${index}`;
+				
+			}
+			
+			attribute = {
+				type,
+				name,
+				index,
+				property
+			};
+			
+			this.attributes[ name ] = attribute;
+			
+		}
 		
-		// uv1 only for now
-		return 'vUv';
+		return attribute;
 		
 	}
 
@@ -153,53 +175,70 @@ class NodeBuilder {
 
 	}
 
-	getUniformsOutput( shaderStage ) {
+	getAttributesBodySnippet( /*shaderStage*/ ) {
 		
-		const uniforms = this.uniforms[ shaderStage ];
 		
-		let uniformsCode = '';
-
-		for ( let i = 0; i < uniforms.length; i ++ ) {
-
-			let uniform = uniforms[ i ];
-
-			uniformsCode += `${uniform.type} ${uniform.name}; `;
+		
+	}
 
-		}
+	getAttributesHeaderSnippet( /*shaderStage*/ ) {
+		
 		
-		return uniformsCode;
 		
 	}
 
-	build( shaderStage ) {
+	getUniformsHeaderSnippet( shaderStage ) {
+		
+		const uniforms = this.uniforms[ shaderStage ];
+		
+		let snippet = '';
+			
+		for ( let uniform of uniforms ) {			
 
-		this.shaderStage = shaderStage;
+			snippet += `${uniform.type} ${uniform.name}; `;
 
-		const slots = this.slots[ shaderStage ];
+		}
+		
+		return snippet;
 		
-		if ( slots.length ) {
+	}
 
-			this.define( shaderStage, 'NODE', VERSION );
+	build() {
 
-			for ( let i = 0; i < slots.length; i ++ ) {
+		const shaderStages = [ 'vertex', 'fragment' ];
+		const shaderData = {};
 
-				let slot = slots[ i ];
+		for ( let shaderStage of shaderStages ) {
+			
+			this.shaderStage = shaderStage;
+			
+			let slots = this.slots[ shaderStage ];
+			
+			for ( let slot of slots ) {
 
 				let flowData = this.flowNode( slot.node, slot.output );
 
 				this.define( shaderStage, `NODE_${slot.name}`, flowData.result );
 
 			}
-
-			this.define( shaderStage, 'NODE_UNIFORMS', this.getUniformsOutput( shaderStage ) );
-
+			
 		}
 
-		let defines = this._buildDefines( shaderStage );
+		for ( let shaderStage of shaderStages ) {
+
+			this.shaderStage = shaderStage;
 
-		return {
-			defines
-		};
+			this.define( shaderStage, 'NODE_HEADER_UNIFORMS', this.getUniformsHeaderSnippet( shaderStage ) );
+			this.define( shaderStage, 'NODE_HEADER_ATTRIBUTES', this.getAttributesHeaderSnippet( shaderStage ) );
+			this.define( shaderStage, 'NODE_BODY_ATTRIBUTES', this.getAttributesBodySnippet( shaderStage ) );
+			
+			shaderData[ shaderStage ] = this._buildDefines( shaderStage );
+			
+		}
+		
+		this.shaderStage = null;
+		
+		return shaderData;
 
 	}
 	

+ 8 - 0
examples/jsm/renderers/nodes/core/constants.js

@@ -0,0 +1,8 @@
+export const NodeType = {
+	Float: 'float',
+	Vector2: 'vec2',
+	Vector3: 'vec3',
+	Vector4: 'vec4',
+	Matrix3: 'matrix3',
+	Matrix4: 'matrix4'
+};

+ 6 - 4
examples/jsm/renderers/nodes/inputs/TextureNode.js

@@ -14,12 +14,14 @@ class TextureNode extends InputNode {
 	
 	generate( builder, output ) {
 	
-		const textureSnippet = super.generate( builder );
-		const uvSnippet = this.uv.build( builder );
+		const type = this.getType( builder );
+	
+		const textureSnippet = super.generate( builder, type );
+		const uvSnippet = this.uv.build( builder, 'vec2' );
 
-		const textureCall = builder.getTexture( textureSnippet, uvSnippet );
+		const textureCallSnippet = builder.getTexture( textureSnippet, uvSnippet );
 
-		return builder.format( textureCall, 'vec4', output );
+		return builder.format( textureCallSnippet, type, output );
 		
 	}
 

+ 16 - 17
examples/jsm/renderers/webgpu/ShaderLib.js

@@ -3,9 +3,9 @@ const ShaderLib = {
 		vertexShader: `#version 450
 
 		layout(location = 0) in vec3 position;
-		layout(location = 1) in vec2 uv;
 
-		layout(location = 0) out vec2 vUv;
+		NODE_HEADER_ATTRIBUTES
+		NODE_HEADER_UNIFORMS
 
 		layout(set = 0, binding = 0) uniform ModelUniforms {
 			mat4 modelMatrix;
@@ -19,14 +19,14 @@ const ShaderLib = {
 		} cameraUniforms;
 
 		void main(){
-			vUv = uv;
+			NODE_BODY_ATTRIBUTES
 			gl_Position = cameraUniforms.projectionMatrix * modelUniforms.modelViewMatrix * vec4( position, 1.0 );
 		}`,
 		fragmentShader: `#version 450
 
-		NODE_UNIFORMS
+		NODE_HEADER_ATTRIBUTES
+		NODE_HEADER_UNIFORMS
 
-		layout(location = 0) in vec2 vUv;
 		layout(location = 0) out vec4 outColor;
 
 		void main() {
@@ -35,13 +35,13 @@ const ShaderLib = {
 
 			#ifdef NODE_COLOR
 
-				outColor.rgb *= NODE_COLOR;
+				outColor.rgb = NODE_COLOR;
 
 			#endif
 
 			#ifdef NODE_OPACITY
 
-				outColor.a *= NODE_OPACITY;
+				outColor.a = NODE_OPACITY;
 
 			#endif
 
@@ -52,6 +52,9 @@ const ShaderLib = {
 
 		layout(location = 0) in vec3 position;
 
+		NODE_HEADER_ATTRIBUTES
+		NODE_HEADER_UNIFORMS
+
 		layout(set = 0, binding = 0) uniform ModelUniforms {
 			mat4 modelMatrix;
 			mat4 modelViewMatrix;
@@ -63,23 +66,19 @@ const ShaderLib = {
 		} cameraUniforms;
 
 		void main(){
+			NODE_BODY_ATTRIBUTES
 			gl_Position = cameraUniforms.projectionMatrix * modelUniforms.modelViewMatrix * vec4( position, 1.0 );
 		}`,
 		fragmentShader: `#version 450
 
-		layout(location = 0) out vec4 outColor;
-
-		#ifdef NODE_UNIFORMS
+		NODE_HEADER_ATTRIBUTES
+		NODE_HEADER_UNIFORMS
 
-		layout(set = 0, binding = 2) uniform NodeUniforms {
-			NODE_UNIFORMS
-		} nodeUniforms;
-
-		#endif
+		layout(location = 0) out vec4 outColor;
 
 		void main() {
 
-			outColor = vec4( 1.0, 0.0, 0.0, 1.0 );
+			outColor = vec4( 1.0, 1.0, 1.0, 1.0 );
 
 			#ifdef NODE_COLOR
 
@@ -89,7 +88,7 @@ const ShaderLib = {
 
 			#ifdef NODE_OPACITY
 
-				outColor.a *= NODE_OPACITY;
+				outColor.a = NODE_OPACITY;
 
 			#endif
 

+ 4 - 25
examples/jsm/renderers/webgpu/WebGPUBindings.js

@@ -43,7 +43,7 @@ class WebGPUBindings {
 
 			} else if ( material.isPointsMaterial ) {
 
-				bindings = this._getPointsBasicBindings();
+				bindings = this._getPointsBasicBindings( object );
 
 			} else if ( material.isLineBasicMaterial ) {
 
@@ -55,10 +55,6 @@ class WebGPUBindings {
 
 			}
 
-			// append node bindings
-
-//			bindings = bindings.concat( this.pipelines.getBindings( object ) );
-
 			// setup (static) binding layout and (dynamic) binding group
 
 			const bindLayout = pipeline.getBindGroupLayout( 0 );
@@ -308,37 +304,19 @@ class WebGPUBindings {
 
 		const cameraGroup = this.sharedUniformsGroups.get( 'cameraUniforms' );
 
-		// material (opacity for testing)
-
-		const opacityUniform = new FloatUniform( 'opacity', 1 );
-
-		const opacityGroup = new WebGPUUniformsGroup( 'opacityUniforms' );
-		opacityGroup.addUniform( opacityUniform );
-		opacityGroup.setVisibility( GPUShaderStage.FRAGMENT );
-		opacityGroup.setOnBeforeUpdate( function ( object/*, camera */ ) {
-
-			const material = object.material;
-			const opacity = ( material.transparent === true ) ? material.opacity : 1.0;
-
-			opacityUniform.setValue( opacity );
-
-		} );
-
 		// the order of WebGPUBinding objects must match the binding order in the shader
 
 		bindings.push( modelGroup );
 		bindings.push( cameraGroup );
 		bindings = bindings.concat( this.pipelines.getBindings( object ) );
-		//bindings.push( diffuseSampler );
-		//bindings.push( diffuseTexture );
 
 		return bindings;
 
 	}
 
-	_getPointsBasicBindings() {
+	_getPointsBasicBindings( object ) {
 
-		const bindings = [];
+		let bindings = [];
 
 		// UBOs
 
@@ -361,6 +339,7 @@ class WebGPUBindings {
 
 		bindings.push( modelGroup );
 		bindings.push( cameraGroup );
+		bindings = bindings.concat( this.pipelines.getBindings( object ) );
 
 		return bindings;
 

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

@@ -11,7 +11,7 @@ import {
 
 import ShaderLib from './ShaderLib.js';
 
-import WebGPUNodeBuilder from './WebGPUNodeBuilder.js';
+import WebGPUNodeBuilder from './nodes/WebGPUNodeBuilder.js';
 
 class WebGPURenderPipelines {
 
@@ -112,7 +112,7 @@ class WebGPURenderPipelines {
 			let moduleFragment = this.shaderModules.fragment.get( shader );
 
 			if ( moduleFragment === undefined ) {
-console.log( shader.fragmentShader );
+
 				const byteCodeFragment = glslang.compileGLSL( shader.fragmentShader, 'fragment' );
 
 				moduleFragment = {
@@ -787,7 +787,7 @@ console.log( shader.fragmentShader );
 
 		// find "layout (location = num) in type name" in vertex shader
 
-		const regex = /^\s*layout\s*\(\s*location\s*=\s*(?<location>[0-9]+)\s*\)\s*in\s+(?<type>\w+)\s+(?<name>\w+)\s*;/gmi;
+		const regex = /\s*layout\s*\(\s*location\s*=\s*(?<location>[0-9]+)\s*\)\s*in\s+(?<type>\w+)\s+(?<name>\w+)\s*;/gmi;
 		let shaderAttribute = null;
 
 		const attributes = [];

+ 7 - 0
examples/jsm/renderers/webgpu/WebGPURenderer.js

@@ -11,6 +11,8 @@ import WebGPURenderLists from './WebGPURenderLists.js';
 import WebGPUTextures from './WebGPUTextures.js';
 import WebGPUBackground from './WebGPUBackground.js';
 
+import WebGPUNodes from './nodes/WebGPUNodes.js';
+
 import { Frustum, Matrix4, Vector3, Color } from '../../../../build/three.module.js';
 
 console.info( 'THREE.WebGPURenderer: Modified Matrix4.makePerspective() and Matrix4.makeOrtographic() to work with WebGPU, see https://github.com/mrdoob/three.js/issues/20276.' );
@@ -97,6 +99,7 @@ class WebGPURenderer {
 		this._properties = null;
 		this._attributes = null;
 		this._geometries = null;
+		this._nodes = null;
 		this._bindings = null;
 		this._objects = null;
 		this._renderPipelines = null;
@@ -177,6 +180,7 @@ class WebGPURenderer {
 		this._objects = new WebGPUObjects( this._geometries, this._info );
 		this._renderPipelines = new WebGPURenderPipelines( this, this._properties, device, compiler, parameters.sampleCount );
 		this._computePipelines = new WebGPUComputePipelines( device, compiler );
+		this._nodes = new WebGPUNodes()
 		this._bindings = new WebGPUBindings( device, this._info, this._properties, this._textures, this._renderPipelines, this._computePipelines, this._attributes );
 		this._renderLists = new WebGPURenderLists();
 		this._background = new WebGPUBackground( this );
@@ -514,6 +518,7 @@ class WebGPURenderer {
 		this._properties.dispose();
 		this._renderPipelines.dispose();
 		this._computePipelines.dispose();
+		this._nodes.dispose();
 		this._bindings.dispose();
 		this._info.dispose();
 		this._renderLists.dispose();
@@ -720,6 +725,7 @@ class WebGPURenderer {
 
 						passEncoder.setViewport( vp.x, vp.y, vp.width, vp.height, minDepth, maxDepth );
 
+						this._nodes.update( object, camera2 );
 						this._bindings.update( object, camera2 );
 						this._renderObject( object, passEncoder );
 
@@ -729,6 +735,7 @@ class WebGPURenderer {
 
 			} else {
 
+				this._nodes.update( object, camera );
 				this._bindings.update( object, camera );
 				this._renderObject( object, passEncoder );
 

+ 2 - 4
examples/jsm/renderers/webgpu/WebGPUUniform.js

@@ -30,11 +30,9 @@ class WebGPUUniform {
 
 class FloatUniform extends WebGPUUniform {
 
-	constructor( nodeUniform ) {
+	constructor( name, value = 0 ) {
 
-		super( nodeUniform.name, nodeUniform.value );
-
-		this.nodeUniform = nodeUniform;
+		super( name, value );
 
 		this.boundary = 4;
 		this.itemSize = 1;

+ 6 - 6
examples/jsm/renderers/webgpu/WebGPUUniformsGroup.js

@@ -146,7 +146,7 @@ class WebGPUUniformsGroup extends WebGPUBinding {
 		let updated = false;
 
 		const a = this.array;
-		const v = uniform.value;
+		const v = uniform.getValue();
 		const offset = uniform.offset;
 
 		if ( a[ offset + 0 ] !== v.x || a[ offset + 1 ] !== v.y ) {
@@ -167,7 +167,7 @@ class WebGPUUniformsGroup extends WebGPUBinding {
 		let updated = false;
 
 		const a = this.array;
-		const v = uniform.value;
+		const v = uniform.getValue();
 		const offset = uniform.offset;
 
 		if ( a[ offset + 0 ] !== v.x || a[ offset + 1 ] !== v.y || a[ offset + 2 ] !== v.z ) {
@@ -189,7 +189,7 @@ class WebGPUUniformsGroup extends WebGPUBinding {
 		let updated = false;
 
 		const a = this.array;
-		const v = uniform.value;
+		const v = uniform.getValue();
 		const offset = uniform.offset;
 
 		if ( a[ offset + 0 ] !== v.x || a[ offset + 1 ] !== v.y || a[ offset + 2 ] !== v.z || a[ offset + 4 ] !== v.w ) {
@@ -212,7 +212,7 @@ class WebGPUUniformsGroup extends WebGPUBinding {
 		let updated = false;
 
 		const a = this.array;
-		const c = uniform.value;
+		const c = uniform.getValue();
 		const offset = uniform.offset;
 
 		if ( a[ offset + 0 ] !== c.r || a[ offset + 1 ] !== c.g || a[ offset + 2 ] !== c.b ) {
@@ -234,7 +234,7 @@ class WebGPUUniformsGroup extends WebGPUBinding {
 		let updated = false;
 
 		const a = this.array;
-		const e = uniform.value.elements;
+		const e = uniform.getValue().elements;
 		const offset = uniform.offset;
 
 		if ( a[ offset + 0 ] !== e[ 0 ] || a[ offset + 1 ] !== e[ 1 ] || a[ offset + 2 ] !== e[ 2 ] ||
@@ -264,7 +264,7 @@ class WebGPUUniformsGroup extends WebGPUBinding {
 		let updated = false;
 
 		const a = this.array;
-		const e = uniform.value.elements;
+		const e = uniform.getValue().elements;
 		const offset = uniform.offset;
 
 		if ( arraysEqual( a, e, offset ) === false ) {

+ 92 - 55
examples/jsm/renderers/webgpu/WebGPUNodeBuilder.js → examples/jsm/renderers/webgpu/nodes/WebGPUNodeBuilder.js

@@ -1,36 +1,10 @@
-import WebGPUUniformsGroup from './WebGPUUniformsGroup.js';
-import { FloatUniform, Vector3Uniform } from './WebGPUUniform.js';
-import WebGPUSampler from './WebGPUSampler.js';
-import { WebGPUSampledTexture } from './WebGPUSampledTexture.js';
+import WebGPUNodeUniformsGroup from './WebGPUNodeUniformsGroup.js';
+import { FloatNodeUniform, Vector2NodeUniform, Vector3NodeUniform, Vector4NodeUniform } from './WebGPUNodeUniform.js';
+import WebGPUSampler from '../WebGPUSampler.js';
+import { WebGPUSampledTexture } from '../WebGPUSampledTexture.js';
 
-import NodeSlot from '../nodes/core/NodeSlot.js';
-import NodeBuilder from '../nodes/core/NodeBuilder.js';
-
-class WebGPUNodeUniformsGroup extends WebGPUUniformsGroup {
-
-	constructor( shaderStage ) {
-
-		super( 'nodeUniforms' );
-
-		let shaderStageVisibility;
-
-		if ( shaderStage === 'vertex' ) shaderStageVisibility = GPUShaderStage.VERTEX;
-		else if ( shaderStage === 'fragment' ) shaderStageVisibility = GPUShaderStage.FRAGMENT;
-
-		this.setVisibility( shaderStageVisibility );
-
-		//this.setOnBeforeUpdate( this._onBeforeUpdate );
-
-	}
-	/*
-	_onBeforeUpdate( object, camera ) {
-
-		const material = object.material;
-
-	}
-	*/
-
-}
+import NodeSlot from '../../nodes/core/NodeSlot.js';
+import NodeBuilder from '../../nodes/core/NodeBuilder.js';
 
 class WebGPUNodeBuilder extends NodeBuilder {
 
@@ -41,8 +15,11 @@ class WebGPUNodeBuilder extends NodeBuilder {
 		this.bindingIndex = 2;
 		this.bindings = { vertex: [], fragment: [] };
 
-		this.uniformsGroup = {};
+		this.attributeIndex = 1;
+		this.varyIndex = 0;
 
+		this.uniformsGroup = {};
+		
 		this._parseMaterial();
 
 	}
@@ -129,11 +106,19 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 				if ( type === 'float' ) {
 
-					uniform = new FloatUniform( uniformNode );
+					uniform = new FloatNodeUniform( uniformNode );
+
+				} else if ( type === 'vec2' ) {
+
+					uniform = new Vector2NodeUniform( uniformNode );
 
 				} else if ( type === 'vec3' ) {
 
-					uniform = new Vector3Uniform( uniformNode.name, uniformNode.value );
+					uniform = new Vector3NodeUniform( uniformNode );
+
+				} else if ( type === 'vec4' ) {
+
+					uniform = new Vector4NodeUniform( uniformNode );
 
 				} else {
 
@@ -153,12 +138,66 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 	}
 
-	getUniformsOutput( shaderStage ) {
+	getAttributesHeaderSnippet( shaderStage ) {
+		
+		let snippet = '';
+		
+		const attributes = this.attributes;
+		
+		let attributeIndex = this.attributeIndex;
+		let varyIndex = this.varyIndex;
+
+		for ( let name in attributes ) {			
+
+			let attribute = attributes[ name ];
+			
+			let type = attribute.type;
+			let property = attribute.property;
+
+			if ( shaderStage === 'vertex' ) {
+				
+				snippet += `layout(location = ${attributeIndex++}) in ${type} ${name};`;
+				snippet += `layout(location = ${varyIndex++}) out ${type} ${property};`;
+				
+			} else if ( shaderStage === 'fragment' ) {
+				
+				snippet += `layout(location = ${varyIndex++}) in ${type} ${property};`;
+				
+			}
+
+		}
+		
+		return snippet;
+		
+	}
+
+	getAttributesBodySnippet( shaderStage ) {
+		
+		let snippet = '';
+		
+		const attributes = this.attributes;
+		
+		for ( let name in attributes ) {			
+
+			let attribute = attributes[ name ];
+
+			let property = attribute.property;
+
+			snippet += `${property} = ${name};`;
+
+		}
+		
+		return snippet;
+		
+	}
+	
+
+	getUniformsHeaderSnippet( shaderStage ) {
 		
 		const uniforms = this.uniforms[ shaderStage ];
 		
-		let uniformsCode = '';
-		let uniformGroupCode = '';
+		let snippet = '';
+		let groupSnippet = '';
 		
 		let bindingIndex = this.bindingIndex;
 
@@ -166,47 +205,43 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 			if (uniform.type === 'texture') {
 
-				uniformsCode += `layout(set = 0, binding = ${bindingIndex++}) uniform sampler ${uniform.name}_sampler;`;
-				uniformsCode += `layout(set = 0, binding = ${bindingIndex++}) uniform texture2D ${uniform.name};`;
+				snippet += `layout(set = 0, binding = ${bindingIndex++}) uniform sampler ${uniform.name}_sampler;`;
+				snippet += `layout(set = 0, binding = ${bindingIndex++}) uniform texture2D ${uniform.name};`;
 
 			} else {
 		
-				if (!uniformGroupCode) {
+				if (!groupSnippet) {
 					
-					uniformGroupCode = `layout(set = 0, binding = ${bindingIndex++}) uniform NodeUniforms {`;
+					groupSnippet = `layout(set = 0, binding = ${bindingIndex++}) uniform NodeUniforms {`;
 					
 				}
 				
-				uniformGroupCode += `uniform ${uniform.type} ${uniform.name};`;
+				groupSnippet += `uniform ${uniform.type} ${uniform.name};`;
 				
 			}
 
 		}
 		
-		if (uniformGroupCode) {
+		if (groupSnippet) {
 			
-			uniformGroupCode += `} nodeUniforms;`;
+			groupSnippet += `} nodeUniforms;`;
 			
-			uniformsCode += uniformGroupCode;
+			snippet += groupSnippet;
 			
 		}
 		
-		console.log( uniformsCode );
-		
-		return uniformsCode;
+		return snippet;
 		
 	}
 
-	buildShader( shaderStage, code ) {
+	buildShader( code, snippet ) {
 
 		// use regex maybe for security?
 		const versionStrIndex = code.indexOf( "\n" );
 
 		let finalCode = code.substr( 0, versionStrIndex ) + "\n\n";
 
-		const shaderCodes = this.build( shaderStage );
-
-		finalCode += shaderCodes.defines;
+		finalCode += snippet;
 
 		finalCode += code.substr( versionStrIndex );
 
@@ -215,9 +250,11 @@ class WebGPUNodeBuilder extends NodeBuilder {
 	}
 
 	parse( vertexShader, fragmentShader ) {
+		
+		const shader = this.build();
 
-		vertexShader = this.buildShader( 'vertex', vertexShader );
-		fragmentShader = this.buildShader( 'fragment', fragmentShader );
+		vertexShader = this.buildShader( vertexShader, shader.vertex );
+		fragmentShader = this.buildShader( fragmentShader, shader.fragment );
 
 		return {
 			vertexShader,

+ 135 - 0
examples/jsm/renderers/webgpu/nodes/WebGPUNodeUniform.js

@@ -0,0 +1,135 @@
+import { 
+	FloatUniform, Vector2Uniform, Vector3Uniform, Vector4Uniform, 
+	ColorUniform, Matrix3Uniform, Matrix4Uniform 
+} from '../WebGPUUniform.js';
+
+class FloatNodeUniform extends FloatUniform {
+
+	constructor( nodeUniform ) {
+
+		super( nodeUniform.name, nodeUniform.value );
+
+		this.nodeUniform = nodeUniform;
+
+	}
+	
+	getValue() {
+		
+		return this.nodeUniform.value;
+		
+	}
+
+}
+
+class Vector2NodeUniform extends Vector2Uniform {
+
+	constructor( nodeUniform ) {
+
+		super( nodeUniform.name, nodeUniform.value );
+
+		this.nodeUniform = nodeUniform;
+
+	}
+	
+	getValue() {
+		
+		return this.nodeUniform.value;
+		
+	}
+
+}
+
+class Vector3NodeUniform extends Vector3Uniform {
+
+	constructor( nodeUniform ) {
+
+		super( nodeUniform.name, nodeUniform.value );
+
+		this.nodeUniform = nodeUniform;
+
+	}
+	
+	getValue() {
+		
+		return this.nodeUniform.value;
+		
+	}
+
+}
+
+class Vector4NodeUniform extends Vector4Uniform {
+
+	constructor( nodeUniform ) {
+
+		super( nodeUniform.name, nodeUniform.value );
+
+		this.nodeUniform = nodeUniform;
+
+	}
+	
+	getValue() {
+		
+		return this.nodeUniform.value;
+		
+	}
+
+}
+
+class ColorNodeUniform extends ColorUniform {
+
+	constructor( nodeUniform ) {
+
+		super( nodeUniform.name, nodeUniform.value );
+
+		this.nodeUniform = nodeUniform;
+
+	}
+	
+	getValue() {
+		
+		return this.nodeUniform.value;
+		
+	}
+
+}
+
+class Matrix3NodeUniform extends Matrix3Uniform {
+
+	constructor( nodeUniform ) {
+
+		super( nodeUniform.name, nodeUniform.value );
+
+		this.nodeUniform = nodeUniform;
+
+	}
+	
+	getValue() {
+		
+		return this.nodeUniform.value;
+		
+	}
+
+}
+
+class Matrix4NodeUniform extends Matrix4Uniform {
+
+	constructor( nodeUniform ) {
+
+		super( nodeUniform.name, nodeUniform.value );
+
+		this.nodeUniform = nodeUniform;
+
+	}
+	
+	getValue() {
+		
+		return this.nodeUniform.value;
+		
+	}
+
+}
+
+export { 
+	FloatNodeUniform, Vector2NodeUniform, Vector3NodeUniform, Vector4NodeUniform, 
+	ColorNodeUniform, Matrix3NodeUniform, Matrix4NodeUniform 
+};

+ 29 - 0
examples/jsm/renderers/webgpu/nodes/WebGPUNodeUniformsGroup.js

@@ -0,0 +1,29 @@
+import WebGPUUniformsGroup from '../WebGPUUniformsGroup.js'
+
+class WebGPUNodeUniformsGroup extends WebGPUUniformsGroup {
+
+	constructor( shaderStage ) {
+
+		super( 'nodeUniforms' );
+
+		let shaderStageVisibility;
+
+		if ( shaderStage === 'vertex' ) shaderStageVisibility = GPUShaderStage.VERTEX;
+		else if ( shaderStage === 'fragment' ) shaderStageVisibility = GPUShaderStage.FRAGMENT;
+
+		this.setVisibility( shaderStageVisibility );
+
+		//this.setOnBeforeUpdate( this._onBeforeUpdate );
+
+	}
+	/*
+	_onBeforeUpdate( object, camera ) {
+
+		const material = object.material;
+
+	}
+	*/
+
+}
+
+export default WebGPUUniformsGroup;

+ 1 - 1
examples/jsm/renderers/webgpu/WebGPUNodes.js → examples/jsm/renderers/webgpu/nodes/WebGPUNodes.js

@@ -7,7 +7,7 @@ class WebGPUNodes {
 
 	}
 
-	get( material ) {
+	get( object ) {
 
 		let data = this.uniformsData.get( object );
 

+ 12 - 3
examples/webgpu_sandbox.html

@@ -19,6 +19,7 @@
 			import WebGPURenderer from './jsm/renderers/webgpu/WebGPURenderer.js';
 			import WebGPU from './jsm/renderers/webgpu/WebGPU.js';
 
+			import AttributeNode from './jsm/renderers/nodes/core/AttributeNode.js';
 			import FloatNode from './jsm/renderers/nodes/inputs/FloatNode.js';
 			import Vector3Node from './jsm/renderers/nodes/inputs/Vector3Node.js';
 			import TextureNode from './jsm/renderers/nodes/inputs/TextureNode.js';
@@ -66,12 +67,17 @@
 				const animateUV = new OperatorNode( '+', new UVNode(), timerScaleNode );
 
 				//materialBox.colorNode = new OperatorNode( '+', new FloatNode( .5 ).setConst( true ), new Vector3Node( new THREE.Vector3( 0, 0, 1 ) ) );
-				materialBox.colorNode = new OperatorNode( '+', new TextureNode( texture, animateUV ), new Vector3Node( new THREE.Vector3( 0, 0, 1 ) ) );
+				materialBox.colorNode = new TextureNode( texture, animateUV );
 				//materialBox.colorNode = new Vector3Node( new THREE.Vector3( 1, 1, 1 ) );
+				//materialBox.colorNode = new FloatNode( .5 );
 				//materialBox.colorNode = new TextureNode( texture );
 				//materialBox.opacityNode = timerNode;
 				materialBox.transparent = true;
 
+				// test attribute
+				//geometryBox.addAttribute( 'uv2', geometryBox.getAttribute( 'uv' ) );
+				//materialBox.colorNode = new TextureNode( texture, new AttributeNode( 'vec2', 'uv2' ) );
+
 				box = new THREE.Mesh( geometryBox, materialBox );
 				box.position.set( 0, 1, 0 );
 				scene.add( box );
@@ -107,14 +113,17 @@
 
 				}
 
+
 				const geometryPoints = new THREE.BufferGeometry().setFromPoints( points );
 				const materialPoints = new THREE.PointsMaterial();
 
-				materialPoints.colorNode = new Vector3Node( new THREE.Vector3( 0, .6, 1 ) );
+				geometryPoints.addAttribute( 'color', geometryPoints.getAttribute( 'position' ) );
+
+				materialPoints.colorNode = new OperatorNode( '+', new TextureNode( texture, new AttributeNode( 'vec3', 'color' ) ), new Vector3Node( new THREE.Vector3( 0, 0, 1 ) ) );
 
 				const pointCloud = new THREE.Points( geometryPoints, materialPoints );
 				pointCloud.position.set( 2, - 1, 0 );
-				//scene.add( pointCloud );
+				scene.add( pointCloud );
 
 				// lines