Ver código fonte

BatchedMesh: Add getInstanceCount/setInstanceCount methods for instanced multi-draw (#28103)

* WebGLRenderer: Backport instanced multi-draw support.

* Updated builds.

* Revert "Updated builds."

This reverts commit ea7e582f96f59bf2c48cbc338969ac8732cd757a.

* Updated builds.

* Revert "Updated builds."

This reverts commit a757862a3a0f4ab0eacffb9262d84f51bc59ae86.

* Examples: restore mesh_batch examples

* BatchedMesh: add getInstanceCount/setInstanceCount methods

* Restore examples, remove builds.
Cody Bennett 1 ano atrás
pai
commit
19c51aa7e9

+ 24 - 0
docs/api/en/objects/BatchedMesh.html

@@ -213,6 +213,30 @@
 			Replaces the geometry at `index` with the provided geometry. Throws an error if there is not enough space reserved for geometry at the index.
 		</p>
 
+		<h3>
+			[method:Integer getInstanceCountAt]( [param:Integer index] )
+		</h3>
+		<p>
+			[page:Integer index]: The index of an instance. Values have to be in the
+			range [0, count].
+		</p>
+		<p>
+			Gets the instance count of the geometry at `index`. Returns `null` if instance counts are not configured.
+		</p>
+
+		<h3>
+			[method:Integer setInstanceCountAt]( [param:Integer index], [param:Integer instanceCount ] )
+		</h3>
+		<p>
+			[page:Integer index]: Which geometry index to configure an instance count for.
+		</p>
+		<p>
+			[page:Integer instanceCount]: The number of instances to render of the given geometry index.
+		</p>
+		<p>
+			Sets an instance count of the geometry at `index`.
+		</p>
+
 		<h2>Source</h2>
 
 		<p>

+ 24 - 0
docs/api/zh/objects/BatchedMesh.html

@@ -191,6 +191,30 @@
 		用提供的几何图形替换 `index` 的几何图形。如果索引处没有为几何体保留足够的空间,则会引发错误。
 	</p>
 
+	<h3>
+		[method:Integer getInstanceCountAt]( [param:Integer index] )
+	</h3>
+	<p>
+		[page:Integer index]: The index of an instance. Values have to be in the
+		range [0, count].
+	</p>
+	<p>
+		Gets the instance count of the geometry at `index`. Returns `null` if instance counts are not configured.
+	</p>
+
+	<h3>
+		[method:Integer setInstanceCountAt]( [param:Integer index], [param:Integer instanceCount ] )
+	</h3>
+	<p>
+		[page:Integer index]: Which geometry index to configure an instance count for.
+	</p>
+	<p>
+		[page:Integer instanceCount]: The number of instances to render of the given geometry index.
+	</p>
+	<p>
+		Sets an instance count of the geometry at `index`.
+	</p>
+
 	<h2>源代码</h2>
 
 	<p>

+ 1 - 10
examples/jsm/renderers/webgl/WebGLBackend.js

@@ -701,16 +701,7 @@ class WebGLBackend extends Backend {
 
 		if ( object.isBatchedMesh ) {
 
-			if ( instanceCount > 1 ) {
-
-				// TODO: Better support with InstancedBatchedMesh
-				if ( object._multiDrawInstances === undefined ) {
-
-					object._multiDrawInstances = new Int32Array( object._maxGeometryCount );
-
-				}
-
-				object._multiDrawInstances.fill( instanceCount );
+			if ( object._multiDrawInstances !== null ) {
 
 				renderer.renderMultiDrawInstances( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount, object._multiDrawInstances );
 

+ 5 - 1
examples/jsm/renderers/webgl/WebGLBufferRenderer.js

@@ -127,7 +127,11 @@ class WebGLBufferRenderer {
 
 			}
 
-			info.update( object, elementCount, mode, primcount );
+			for ( let i = 0; i < primcount.length; i ++ ) {
+
+				info.update( object, elementCount, mode, primcount[ i ] );
+
+			}
 
 		}
 

+ 23 - 0
src/objects/BatchedMesh.js

@@ -152,6 +152,7 @@ class BatchedMesh extends Mesh {
 		this._multiDrawCounts = new Int32Array( maxGeometryCount );
 		this._multiDrawStarts = new Int32Array( maxGeometryCount );
 		this._multiDrawCount = 0;
+		this._multiDrawInstances = null;
 		this._visibilityChanged = true;
 
 		// Local matrix per geometry by using data texture
@@ -593,6 +594,28 @@ class BatchedMesh extends Mesh {
 
 	}
 
+	getInstanceCountAt( id ) {
+
+		if ( this._multiDrawInstances === null ) return null;
+
+		return this._multiDrawInstances[ id ];
+
+	}
+
+	setInstanceCountAt( id, instanceCount ) {
+
+		if ( this._multiDrawInstances === null ) {
+
+			this._multiDrawInstances = new Int32Array( this._maxGeometryCount ).fill( 1 );
+
+		}
+
+		this._multiDrawInstances[ id ] = instanceCount;
+
+		return id;
+
+	}
+
 	// get bounding box and compute it if it doesn't exist
 	getBoundingBoxAt( id, target ) {
 

+ 9 - 1
src/renderers/WebGLRenderer.js

@@ -856,7 +856,15 @@ class WebGLRenderer {
 
 			if ( object.isBatchedMesh ) {
 
-				renderer.renderMultiDraw( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount );
+				if ( object._multiDrawInstances !== null ) {
+
+					renderer.renderMultiDrawInstances( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount, object._multiDrawInstances );
+
+				} else {
+
+					renderer.renderMultiDraw( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount );
+
+				}
 
 			} else if ( object.isInstancedMesh ) {
 

+ 36 - 0
src/renderers/webgl/WebGLBufferRenderer.js

@@ -57,12 +57,48 @@ function WebGLBufferRenderer( gl, extensions, info ) {
 
 	}
 
+	function renderMultiDrawInstances( starts, counts, drawCount, primcount ) {
+
+		if ( drawCount === 0 ) return;
+
+		const extension = extensions.get( 'WEBGL_multi_draw' );
+
+		if ( extension === null ) {
+
+			for ( let i = 0; i < starts.length; i ++ ) {
+
+				renderInstances( starts[ i ], counts[ i ], primcount[ i ] );
+
+			}
+
+		} else {
+
+			extension.multiDrawArraysInstancedWEBGL( mode, starts, 0, counts, 0, primcount, 0, drawCount );
+
+			let elementCount = 0;
+			for ( let i = 0; i < drawCount; i ++ ) {
+
+				elementCount += counts[ i ];
+
+			}
+
+			for ( let i = 0; i < primcount.length; i ++ ) {
+
+				info.update( elementCount, mode, primcount[ i ] );
+
+			}
+
+		}
+
+	}
+
 	//
 
 	this.setMode = setMode;
 	this.render = render;
 	this.renderInstances = renderInstances;
 	this.renderMultiDraw = renderMultiDraw;
+	this.renderMultiDrawInstances = renderMultiDrawInstances;
 
 }
 

+ 36 - 0
src/renderers/webgl/WebGLIndexedBufferRenderer.js

@@ -66,6 +66,41 @@ function WebGLIndexedBufferRenderer( gl, extensions, info ) {
 
 	}
 
+	function renderMultiDrawInstances( starts, counts, drawCount, primcount ) {
+
+		if ( drawCount === 0 ) return;
+
+		const extension = extensions.get( 'WEBGL_multi_draw' );
+
+		if ( extension === null ) {
+
+			for ( let i = 0; i < starts.length; i ++ ) {
+
+				renderInstances( starts[ i ] / bytesPerElement, counts[ i ], primcount[ i ] );
+
+			}
+
+		} else {
+
+			extension.multiDrawElementsInstancedWEBGL( mode, counts, 0, type, starts, 0, primcount, 0, drawCount );
+
+			let elementCount = 0;
+			for ( let i = 0; i < drawCount; i ++ ) {
+
+				elementCount += counts[ i ];
+
+			}
+
+			for ( let i = 0; i < primcount.length; i ++ ) {
+
+				info.update( elementCount, mode, primcount[ i ] );
+
+			}
+
+		}
+
+	}
+
 	//
 
 	this.setMode = setMode;
@@ -73,6 +108,7 @@ function WebGLIndexedBufferRenderer( gl, extensions, info ) {
 	this.render = render;
 	this.renderInstances = renderInstances;
 	this.renderMultiDraw = renderMultiDraw;
+	this.renderMultiDrawInstances = renderMultiDrawInstances;
 
 }