Просмотр исходного кода

WebGPURenderer: Added DynamicDrawUsage and revisions (#26057)

* Nodes: Remove unnecessary call of .getConstNodeType()

* InstanceIndexNode: Fragment stage support

* RangeNode: Move bufferAttribute to buffer

* NodeBuilder: Removed .isShaderStage()

* WebGPURenderer: Added DynamicDrawUsage and dynamicBufferAttribute()
sunag 2 лет назад
Родитель
Сommit
72af345251

+ 1 - 1
examples/jsm/nodes/Nodes.js

@@ -63,7 +63,7 @@ export * from './shadernode/ShaderNode.js';
 
 // accessors
 export { default as BitangentNode, bitangentGeometry, bitangentLocal, bitangentView, bitangentWorld, transformedBitangentView, transformedBitangentWorld } from './accessors/BitangentNode.js';
-export { default as BufferAttributeNode, bufferAttribute } from './accessors/BufferAttributeNode.js';
+export { default as BufferAttributeNode, bufferAttribute, dynamicBufferAttribute } from './accessors/BufferAttributeNode.js';
 export { default as BufferNode, buffer } from './accessors/BufferNode.js';
 export { default as CameraNode, cameraProjectionMatrix, cameraViewMatrix, cameraNormalMatrix, cameraWorldMatrix, cameraPosition } from './accessors/CameraNode.js';
 export { default as CubeTextureNode, cubeTexture } from './accessors/CubeTextureNode.js';

+ 14 - 2
examples/jsm/nodes/accessors/BufferAttributeNode.js

@@ -2,7 +2,7 @@ import InputNode from '../core/InputNode.js';
 import { addNodeClass } from '../core/Node.js';
 import { varying } from '../core/VaryingNode.js';
 import { nodeObject } from '../shadernode/ShaderNode.js';
-import { InterleavedBufferAttribute, InterleavedBuffer } from 'three';
+import { InterleavedBufferAttribute, InterleavedBuffer, StaticDrawUsage, DynamicDrawUsage } from 'three';
 
 class BufferAttributeNode extends InputNode {
 
@@ -16,6 +16,8 @@ class BufferAttributeNode extends InputNode {
 		this.bufferStride = bufferStride;
 		this.bufferOffset = bufferOffset;
 
+		this.usage = StaticDrawUsage;
+
 	}
 
 	construct( builder ) {
@@ -29,6 +31,8 @@ class BufferAttributeNode extends InputNode {
 		const buffer = new InterleavedBuffer( array, stride );
 		const bufferAttribute = new InterleavedBufferAttribute( buffer, itemSize, offset );
 
+		buffer.setUsage( this.usage );
+
 		this.attribute = bufferAttribute;
 		this.attribute.isInstancedBufferAttribute = true; // @TODO: Add a possible: InstancedInterleavedBufferAttribute
 
@@ -43,7 +47,7 @@ class BufferAttributeNode extends InputNode {
 
 		let output = null;
 
-		if ( builder.isShaderStage( 'vertex' ) ) {
+		if ( builder.shaderStage === 'vertex' ) {
 
 			output = propertyName;
 
@@ -70,5 +74,13 @@ class BufferAttributeNode extends InputNode {
 export default BufferAttributeNode;
 
 export const bufferAttribute = ( array, type, stride, offset ) => nodeObject( new BufferAttributeNode( array, type, stride, offset ) );
+export const dynamicBufferAttribute = ( array, type, stride, offset ) => {
+
+	const node = bufferAttribute( array, type, stride, offset );
+	node.usage = DynamicDrawUsage;
+
+	return node;
+
+};
 
 addNodeClass( BufferAttributeNode );

+ 2 - 2
examples/jsm/nodes/accessors/BufferNode.js

@@ -1,6 +1,6 @@
 import UniformNode from '../core/UniformNode.js';
 import { addNodeClass } from '../core/Node.js';
-import { nodeObject, getConstNodeType } from '../shadernode/ShaderNode.js';
+import { nodeObject } from '../shadernode/ShaderNode.js';
 
 class BufferNode extends UniformNode {
 
@@ -25,6 +25,6 @@ class BufferNode extends UniformNode {
 
 export default BufferNode;
 
-export const buffer = ( value, nodeOrType, count ) => nodeObject( new BufferNode( value, getConstNodeType( nodeOrType ), count ) );
+export const buffer = ( value, type, count ) => nodeObject( new BufferNode( value, type, count ) );
 
 addNodeClass( BufferNode );

+ 26 - 13
examples/jsm/nodes/accessors/InstanceNode.js

@@ -1,8 +1,9 @@
 import Node, { addNodeClass } from '../core/Node.js';
-import { bufferAttribute } from './BufferAttributeNode.js';
+import { bufferAttribute, dynamicBufferAttribute } from './BufferAttributeNode.js';
 import { normalLocal } from './NormalNode.js';
 import { positionLocal } from './PositionNode.js';
 import { nodeProxy, vec3, mat3, mat4 } from '../shadernode/ShaderNode.js';
+import { DynamicDrawUsage } from 'three';
 
 class InstanceNode extends Node {
 
@@ -12,23 +13,35 @@ class InstanceNode extends Node {
 
 		this.instanceMesh = instanceMesh;
 
-		//
-
-		const instanceBuffers = [
-			// F.Signature -> bufferAttribute( array, type, stride, offset )
-			bufferAttribute( instanceMesh.instanceMatrix.array, 'vec4', 16, 0 ),
-			bufferAttribute( instanceMesh.instanceMatrix.array, 'vec4', 16, 4 ),
-			bufferAttribute( instanceMesh.instanceMatrix.array, 'vec4', 16, 8 ),
-			bufferAttribute( instanceMesh.instanceMatrix.array, 'vec4', 16, 12 )
-		];
-
-		this.instanceMatrixNode = mat4( ...instanceBuffers );
+		this.instanceMatrixNode = null;
 
 	}
 
 	construct( builder ) {
 
-		const { instanceMatrixNode } = this;
+		let instanceMatrixNode = this.instanceMatrixNode;
+
+		if ( instanceMatrixNode === null ) {
+
+			const instanceMesh = this.instanceMesh;
+			const instaceAttribute = instanceMesh.instanceMatrix;
+			const array = instaceAttribute.array;
+
+			const bufferFn = instaceAttribute.usage === DynamicDrawUsage ? dynamicBufferAttribute : bufferAttribute;
+
+			const instanceBuffers = [
+				// F.Signature -> bufferAttribute( array, type, stride, offset )
+				bufferFn( array, 'vec4', 16, 0 ),
+				bufferFn( array, 'vec4', 16, 4 ),
+				bufferFn( array, 'vec4', 16, 8 ),
+				bufferFn( array, 'vec4', 16, 12 )
+			];
+
+			instanceMatrixNode = mat4( ...instanceBuffers );
+
+			this.instanceMatrixNode = instanceMatrixNode;
+
+		}
 
 		// POSITION
 

+ 2 - 2
examples/jsm/nodes/accessors/MaterialReferenceNode.js

@@ -1,6 +1,6 @@
 import ReferenceNode from './ReferenceNode.js';
 import { addNodeClass } from '../core/Node.js';
-import { nodeObject, getConstNodeType } from '../shadernode/ShaderNode.js';
+import { nodeObject } from '../shadernode/ShaderNode.js';
 
 class MaterialReferenceNode extends ReferenceNode {
 
@@ -34,6 +34,6 @@ class MaterialReferenceNode extends ReferenceNode {
 
 export default MaterialReferenceNode;
 
-export const materialReference = ( name, nodeOrType, material ) => nodeObject( new MaterialReferenceNode( name, getConstNodeType( nodeOrType ), material ) );
+export const materialReference = ( name, type, material ) => nodeObject( new MaterialReferenceNode( name, type, material ) );
 
 addNodeClass( MaterialReferenceNode );

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

@@ -2,7 +2,7 @@ import Node, { addNodeClass } from '../core/Node.js';
 import { NodeUpdateType } from '../core/constants.js';
 import { uniform } from '../core/UniformNode.js';
 import { texture } from './TextureNode.js';
-import { nodeObject, getConstNodeType } from '../shadernode/ShaderNode.js';
+import { nodeObject } from '../shadernode/ShaderNode.js';
 
 class ReferenceNode extends Node {
 
@@ -67,6 +67,6 @@ class ReferenceNode extends Node {
 
 export default ReferenceNode;
 
-export const reference = ( name, nodeOrType, object ) => nodeObject( new ReferenceNode( name, getConstNodeType( nodeOrType ), object ) );
+export const reference = ( name, type, object ) => nodeObject( new ReferenceNode( name, type, object ) );
 
 addNodeClass( ReferenceNode );

+ 2 - 2
examples/jsm/nodes/accessors/StorageBufferNode.js

@@ -1,6 +1,6 @@
 import BufferNode from './BufferNode.js';
 import { addNodeClass } from '../core/Node.js';
-import { nodeObject, getConstNodeType } from '../shadernode/ShaderNode.js';
+import { nodeObject } from '../shadernode/ShaderNode.js';
 
 class StorageBufferNode extends BufferNode {
 
@@ -22,6 +22,6 @@ class StorageBufferNode extends BufferNode {
 
 export default StorageBufferNode;
 
-export const storage = ( value, nodeOrType, count ) => nodeObject( new StorageBufferNode( value, getConstNodeType( nodeOrType ), count ) );
+export const storage = ( value, type, count ) => nodeObject( new StorageBufferNode( value, type, count ) );
 
 addNodeClass( StorageBufferNode );

+ 1 - 1
examples/jsm/nodes/core/AttributeNode.js

@@ -71,7 +71,7 @@ class AttributeNode extends Node {
 
 			const nodeAttribute = builder.getAttribute( attributeName, attributeType );
 
-			if ( builder.isShaderStage( 'vertex' ) ) {
+			if ( builder.shaderStage === 'vertex' ) {
 
 				return builder.format( nodeAttribute.name, attributeType, nodeType );
 

+ 20 - 1
examples/jsm/nodes/core/InstanceIndexNode.js

@@ -1,4 +1,5 @@
 import Node, { addNodeClass } from './Node.js';
+import { varying } from '../core/VaryingNode.js';
 import { nodeImmutable } from '../shadernode/ShaderNode.js';
 
 class InstanceIndexNode extends Node {
@@ -13,7 +14,25 @@ class InstanceIndexNode extends Node {
 
 	generate( builder ) {
 
-		return builder.getInstanceIndex();
+		const nodeType = this.getNodeType( builder );
+
+		const propertyName = builder.getInstanceIndex();
+
+		let output = null;
+
+		if ( builder.shaderStage === 'vertex' || builder.shaderStage === 'compute' ) {
+
+			output = propertyName;
+
+		} else {
+
+			const nodeVarying = varying( this );
+
+			output = nodeVarying.build( builder, nodeType );
+
+		}
+
+		return output;
 
 	}
 

+ 0 - 6
examples/jsm/nodes/core/NodeBuilder.js

@@ -360,12 +360,6 @@ class NodeBuilder {
 
 	}
 
-	isShaderStage( shaderStage ) {
-
-		return this.shaderStage === shaderStage;
-
-	}
-
 	/** @deprecated, r152 */
 	getTextureEncodingFromMap( map ) {
 

+ 2 - 2
examples/jsm/nodes/core/PropertyNode.js

@@ -1,5 +1,5 @@
 import Node, { addNodeClass } from './Node.js';
-import { nodeImmutable, nodeObject, getConstNodeType } from '../shadernode/ShaderNode.js';
+import { nodeImmutable, nodeObject } from '../shadernode/ShaderNode.js';
 
 class PropertyNode extends Node {
 
@@ -42,7 +42,7 @@ class PropertyNode extends Node {
 
 export default PropertyNode;
 
-export const property = ( type, name ) => nodeObject( new PropertyNode( getConstNodeType( type ), name ) );
+export const property = ( type, name ) => nodeObject( new PropertyNode( type, name ) );
 
 export const diffuseColor = nodeImmutable( PropertyNode, 'vec4', 'DiffuseColor' );
 export const roughness = nodeImmutable( PropertyNode, 'float', 'Roughness' );

+ 33 - 38
examples/jsm/nodes/geometry/RangeNode.js

@@ -1,9 +1,14 @@
 import Node, { addNodeClass } from '../core/Node.js';
 import { getValueType } from '../core/NodeUtils.js';
-import { bufferAttribute } from '../accessors/BufferAttributeNode.js';
+import { buffer } from '../accessors/BufferNode.js';
+//import { bufferAttribute } from '../accessors/BufferAttributeNode.js';
+import { instanceIndex } from '../core/InstanceIndexNode.js';
 import { nodeProxy, float } from '../shadernode/ShaderNode.js';
 
-import { MathUtils } from 'three';
+import { Vector4, MathUtils } from 'three';
+
+let min = null;
+let max = null;
 
 class RangeNode extends Node {
 
@@ -39,56 +44,46 @@ class RangeNode extends Node {
 
 		if ( object.isInstancedMesh === true ) {
 
-			let min = this.minNode.value;
-			let max = this.maxNode.value;
-
-			const minLength = builder.getTypeLength( getValueType( min ) );
-			const maxLength = builder.getTypeLength( getValueType( max ) );
-
-				 if ( minLength > maxLength && maxLength > 1 ) max = new min.constructor().fromArray( min.toArray() );
-			else if ( minLength > maxLength && maxLength === 1 ) max = new min.constructor().setScalar( max );
-			else if ( maxLength > minLength && minLength > 1 ) min = new max.constructor().fromArray( min.toArray() );
-			else if ( maxLength > minLength && minLength === 1 ) min = new max.constructor().setScalar( min );
-
-			const vectorLength = this.getVectorLength( builder );
-
-			const length = vectorLength * object.count;
-			const array = new Float32Array( length );
+			let minValue = this.minNode.value;
+			let maxValue = this.maxNode.value;
 
-			if ( vectorLength === 1 ) {
+			const minLength = builder.getTypeLength( getValueType( minValue ) );
+			const maxLength = builder.getTypeLength( getValueType( maxValue ) );
 
-				for ( let i = 0; i < length; i ++ ) {
+			min = min || new Vector4();
+			max = max || new Vector4();
 
-					array[ i ] = MathUtils.lerp( min, max, Math.random() );
+			min.setScalar( 0 );
+			max.setScalar( 0 );
 
-				}
+			if ( minLength === 1 ) min.setScalar( minValue );
+			else if ( minValue.isColor ) min.set( minValue.r, minValue.g, minValue.b );
+			else min.set( minValue.x, minValue.y, minValue.z || 0, minValue.w || 0 );
 
-			} else if ( min.isColor ) {
+			if ( maxLength === 1 ) max.setScalar( maxValue );
+			else if ( maxValue.isColor ) max.set( maxValue.r, maxValue.g, maxValue.b );
+			else max.set( maxValue.x, maxValue.y, maxValue.z || 0, maxValue.w || 0 );
 
-				for ( let i = 0; i < length; i += 3 ) {
+			const stride = 4;
 
-					array[ i ] = MathUtils.lerp( min.r, max.r, Math.random() );
-					array[ i + 1 ] = MathUtils.lerp( min.g, max.g, Math.random() );
-					array[ i + 2 ] = MathUtils.lerp( min.b, max.b, Math.random() );
-
-				}
-
-			} else {
-
-				for ( let i = 0; i < length; i ++ ) {
+			const length = stride * object.count;
+			const array = new Float32Array( length );
 
-					const index = i % vectorLength;
+			for ( let i = 0; i < length; i ++ ) {
 
-					const minValue = min.getComponent( index );
-					const maxValue = max.getComponent( index );
+				const index = i % stride;
 
-					array[ i ] = MathUtils.lerp( minValue, maxValue, Math.random() );
+				const minElementValue = min.getComponent( index );
+				const maxElementValue = max.getComponent( index );
 
-				}
+				array[ i ] = MathUtils.lerp( minElementValue, maxElementValue, Math.random() );
 
 			}
 
-			output = bufferAttribute( array, builder.getTypeFromLength( vectorLength ) );
+			const nodeType = this.getNodeType( builder );
+
+			output = buffer( array, 'vec4', object.count ).element( instanceIndex ).convert( nodeType );
+			//output = bufferAttribute( array, 'vec4', 4, 0 ).convert( nodeType );
 
 		} else {
 

+ 26 - 24
examples/jsm/renderers/webgpu/WebGPUAttributes.js

@@ -1,3 +1,5 @@
+import { DynamicDrawUsage } from "three";
+
 class WebGPUAttributes {
 
 	constructor( device ) {
@@ -9,59 +11,59 @@ class WebGPUAttributes {
 
 	get( attribute ) {
 
-		attribute = this._getAttribute( attribute );
+		const bufferAttribute = this._getBufferAttribute( attribute );
 
-		return this.buffers.get( attribute );
+		return this.buffers.get( bufferAttribute );
 
 	}
 
 	remove( attribute ) {
 
-		attribute = this._getAttribute( attribute );
+		const bufferAttribute = this._getBufferAttribute( attribute );
 
-		const data = this.buffers.get( attribute );
+		const data = this.buffers.get( bufferAttribute );
 
 		if ( data ) {
 
 			this._destroyBuffers( data );
 
-			this.buffers.delete( attribute );
+			this.buffers.delete( bufferAttribute );
 
 		}
 
 	}
 
-	update( attribute, isIndex = false, usage = null ) {
+	update( attribute, isIndex = false, gpuUsage = null ) {
 
-		attribute = this._getAttribute( attribute );
+		const bufferAttribute = this._getBufferAttribute( attribute );
 
-		let data = this.buffers.get( attribute );
+		let data = this.buffers.get( bufferAttribute );
 
 		if ( data === undefined ) {
 
-			if ( usage === null ) {
+			if ( gpuUsage === null ) {
 
-				usage = ( isIndex === true ) ? GPUBufferUsage.INDEX : GPUBufferUsage.VERTEX;
+				gpuUsage = ( isIndex === true ) ? GPUBufferUsage.INDEX : GPUBufferUsage.VERTEX;
 
 			}
 
-			data = this._createBuffer( attribute, usage );
+			data = this._createBuffer( bufferAttribute, gpuUsage );
 
-			this.buffers.set( attribute, data );
+			this.buffers.set( bufferAttribute, data );
 
-		} else if ( usage && usage !== data.usage ) {
+		} else if ( gpuUsage && gpuUsage !== data.usage ) {
 
 			this._destroyBuffers( data );
 
-			data = this._createBuffer( attribute, usage );
+			data = this._createBuffer( bufferAttribute, gpuUsage );
 
-			this.buffers.set( attribute, data );
+			this.buffers.set( bufferAttribute, data );
 
-		} else if ( data.version < attribute.version ) {
+		} else if ( data.version < bufferAttribute.version || bufferAttribute.usage === DynamicDrawUsage ) {
 
-			this._writeBuffer( data.buffer, attribute );
+			this._writeBuffer( data.buffer, bufferAttribute );
 
-			data.version = attribute.version;
+			data.version = bufferAttribute.version;
 
 		}
 
@@ -115,7 +117,7 @@ class WebGPUAttributes {
 
 	}
 
-	_getAttribute( attribute ) {
+	_getBufferAttribute( attribute ) {
 
 		if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;
 
@@ -123,13 +125,13 @@ class WebGPUAttributes {
 
 	}
 
-	_createBuffer( attribute, usage ) {
+	_createBuffer( bufferAttribute, usage ) {
 
-		const array = attribute.array;
+		const array = bufferAttribute.array;
 		const size = array.byteLength + ( ( 4 - ( array.byteLength % 4 ) ) % 4 ); // ensure 4 byte alignment, see #20441
 
 		const buffer = this.device.createBuffer( {
-			label: attribute.name,
+			label: bufferAttribute.name,
 			size,
 			usage: usage | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
 			mappedAtCreation: true
@@ -139,10 +141,10 @@ class WebGPUAttributes {
 
 		buffer.unmap();
 
-		attribute.onUploadCallback();
+		bufferAttribute.onUploadCallback();
 
 		return {
-			version: attribute.version,
+			version: bufferAttribute.version,
 			buffer,
 			readBuffer: null,
 			usage

+ 9 - 1
examples/jsm/renderers/webgpu/nodes/WebGPUNodeBuilder.js

@@ -506,7 +506,15 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 				if ( varying.needsInterpolation ) {
 
-					snippets.push( `@location( ${index} ) ${ varying.name } : ${ this.getType( varying.type ) }` );
+					let attributesSnippet = `@location( ${index} )`;
+
+					if ( varying.type === 'int' || varying.type === 'uint' ) {
+
+						attributesSnippet += ' @interpolate( flat )';
+
+					}
+
+					snippets.push( `${ attributesSnippet } ${ varying.name } : ${ this.getType( varying.type ) }` );
 
 				} else if ( vars.includes( varying ) === false ) {
 

+ 2 - 0
examples/webgpu_instance_mesh.html

@@ -74,6 +74,8 @@
 					geometry.scale( 0.5, 0.5, 0.5 );
 
 					mesh = new THREE.InstancedMesh( geometry, material, count );
+					mesh.instanceMatrix.setUsage( THREE.DynamicDrawUsage );
+
 					scene.add( mesh );
 
 					//