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

WebGPURenderer: Introduce indirect drawing support (#29615)

* introduce indirect drawing support

* Update webgpu_particles.jpg

* update includes

* Update webgpu_particles.html
sunag 1 год назад
Родитель
Сommit
f4afcaa95f

BIN
examples/screenshots/webgpu_particles.jpg


+ 21 - 3
examples/webgpu_particles.html

@@ -89,22 +89,40 @@
 
 				//
 
+				const fireGeometry = new THREE.PlaneGeometry( 1, 1 );
+				const fireCount = 1000;
+
 				const fireNodeMaterial = new THREE.SpriteNodeMaterial();
 				fireNodeMaterial.colorNode = mix( color( 0xb72f17 ), color( 0xb72f17 ), life );
 				fireNodeMaterial.positionNode = range( new THREE.Vector3( - 1, 1, - 1 ), new THREE.Vector3( 1, 2, 1 ) ).mul( lifeTime );
 				fireNodeMaterial.scaleNode = smokeNodeMaterial.scaleNode;
-				fireNodeMaterial.opacityNode = opacityNode;
+				fireNodeMaterial.opacityNode = opacityNode.mul( .5 );
 				fireNodeMaterial.blending = THREE.AdditiveBlending;
 				fireNodeMaterial.transparent = true;
 				fireNodeMaterial.depthWrite = false;
 
-				const fireInstancedSprite = new THREE.Mesh( new THREE.PlaneGeometry( 1, 1 ), fireNodeMaterial );
+				const fireInstancedSprite = new THREE.Mesh( fireGeometry, fireNodeMaterial );
 				fireInstancedSprite.scale.setScalar( 400 );
-				fireInstancedSprite.count = 100;
+				fireInstancedSprite.count = fireCount;
 				fireInstancedSprite.position.y = - 100;
 				fireInstancedSprite.renderOrder = 1;
 				scene.add( fireInstancedSprite );
 
+				// indirect draw ( optional )
+				// each indirect draw call is 5 uint32 values for indexes ( different structure for non-indexed draw calls using 4 uint32 values )
+
+				const indexCount = fireGeometry.index.array.length;
+
+				const uint32 = new Uint32Array( 5 );
+				uint32[ 0 ] = indexCount;	// indexCount
+				uint32[ 1 ] = fireCount; 	// instanceCount
+				uint32[ 2 ] = 0;			// firstIndex
+				uint32[ 3 ] = 0;			// baseVertex
+				uint32[ 4 ] = 0;			// firstInstance
+
+				const indirectAttribute = new THREE.IndirectStorageBufferAttribute( uint32, 5 );
+				fireGeometry.setIndirect( indirectAttribute );
+
 				//
 
 				const helper = new THREE.GridHelper( 3000, 40, 0x303030, 0x303030 );

+ 1 - 0
src/Three.WebGPU.Nodes.js

@@ -172,6 +172,7 @@ export { PostProcessingUtils };
 export { default as StorageTexture } from './renderers/common/StorageTexture.js';
 export { default as StorageBufferAttribute } from './renderers/common/StorageBufferAttribute.js';
 export { default as StorageInstancedBufferAttribute } from './renderers/common/StorageInstancedBufferAttribute.js';
+export { default as IndirectStorageBufferAttribute } from './renderers/common/IndirectStorageBufferAttribute.js';
 export { default as IESSpotLight } from './lights/webgpu/IESSpotLight.js';
 export { default as NodeLoader } from './loaders/nodes/NodeLoader.js';
 export { default as NodeObjectLoader } from './loaders/nodes/NodeObjectLoader.js';

+ 1 - 0
src/Three.WebGPU.js

@@ -173,6 +173,7 @@ export { PostProcessingUtils };
 export { default as StorageTexture } from './renderers/common/StorageTexture.js';
 export { default as StorageBufferAttribute } from './renderers/common/StorageBufferAttribute.js';
 export { default as StorageInstancedBufferAttribute } from './renderers/common/StorageInstancedBufferAttribute.js';
+export { default as IndirectStorageBufferAttribute } from './renderers/common/IndirectStorageBufferAttribute.js';
 export { default as IESSpotLight } from './lights/webgpu/IESSpotLight.js';
 export { default as NodeLoader } from './loaders/nodes/NodeLoader.js';
 export { default as NodeObjectLoader } from './loaders/nodes/NodeObjectLoader.js';

+ 15 - 0
src/core/BufferGeometry.js

@@ -35,6 +35,7 @@ class BufferGeometry extends EventDispatcher {
 		this.type = 'BufferGeometry';
 
 		this.index = null;
+		this.indirect = null;
 		this.attributes = {};
 
 		this.morphAttributes = {};
@@ -73,6 +74,20 @@ class BufferGeometry extends EventDispatcher {
 
 	}
 
+	setIndirect( indirect ) {
+
+		this.indirect = indirect;
+
+		return this;
+
+	}
+
+	getIndirect() {
+
+		return this.indirect;
+
+	}
+
 	getAttribute( name ) {
 
 		return this.attributes[ name ];

+ 20 - 0
src/renderers/common/Geometries.js

@@ -144,6 +144,8 @@ class Geometries extends DataMap {
 
 	updateAttributes( renderObject ) {
 
+		// attributes
+
 		const attributes = renderObject.getAttributes();
 
 		for ( const attribute of attributes ) {
@@ -160,6 +162,8 @@ class Geometries extends DataMap {
 
 		}
 
+		// indexes
+
 		const index = this.getIndex( renderObject );
 
 		if ( index !== null ) {
@@ -168,6 +172,16 @@ class Geometries extends DataMap {
 
 		}
 
+		// indirect
+
+		const indirect = renderObject.geometry.indirect;
+
+		if ( indirect !== null ) {
+
+			this.updateAttribute( indirect, AttributeType.INDIRECT );
+
+		}
+
 	}
 
 	updateAttribute( attribute, type ) {
@@ -206,6 +220,12 @@ class Geometries extends DataMap {
 
 	}
 
+	getIndirect( renderObject ) {
+
+		return renderObject.geometry.indirect;
+
+	}
+
 	getIndex( renderObject ) {
 
 		const { geometry, material } = renderObject;

+ 6 - 0
src/renderers/common/RenderObject.js

@@ -150,6 +150,12 @@ export default class RenderObject {
 
 	}
 
+	getIndirect() {
+
+		return this._geometries.getIndirect( this );
+
+	}
+
 	getChainArray() {
 
 		return [ this.object, this.material, this.context, this.lightsNode ];

+ 26 - 2
src/renderers/webgpu/WebGPUBackend.js

@@ -972,7 +972,19 @@ class WebGPUBackend extends Backend {
 
 			const { vertexCount: indexCount, instanceCount, firstVertex: firstIndex } = drawParams;
 
-			passEncoderGPU.drawIndexed( indexCount, instanceCount, firstIndex, 0, 0 );
+			const indirect = renderObject.getIndirect();
+
+			if ( indirect !== null ) {
+
+				const buffer = this.get( indirect ).buffer;
+
+				passEncoderGPU.drawIndexedIndirect( buffer, 0 );
+
+			} else {
+
+				passEncoderGPU.drawIndexed( indexCount, instanceCount, firstIndex, 0, 0 );
+
+			}
 
 			info.update( object, indexCount, instanceCount );
 
@@ -980,7 +992,19 @@ class WebGPUBackend extends Backend {
 
 			const { vertexCount, instanceCount, firstVertex } = drawParams;
 
-			passEncoderGPU.draw( vertexCount, instanceCount, firstVertex, 0 );
+			const indirect = renderObject.getIndirect();
+
+			if ( indirect !== null ) {
+
+				const buffer = this.get( indirect ).buffer;
+
+				passEncoderGPU.drawIndirect( buffer, 0 );
+
+			} else {
+
+				passEncoderGPU.draw( vertexCount, instanceCount, firstVertex, 0 );
+
+			}
 
 			info.update( object, vertexCount, instanceCount );
 

粤ICP备19079148号