Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 11 commits into from
Apr 15, 2024
24 changes: 24 additions & 0 deletions docs/api/en/objects/BatchedMesh.html
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,30 @@ <h3>
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>
Expand Down
24 changes: 24 additions & 0 deletions docs/api/zh/objects/BatchedMesh.html
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,30 @@ <h3>
用提供的几何图形替换 `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>
Expand Down
11 changes: 1 addition & 10 deletions examples/jsm/renderers/webgl/WebGLBackend.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 );

Expand Down
6 changes: 5 additions & 1 deletion examples/jsm/renderers/webgl/WebGLBufferRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 ] );

}

}

Expand Down
23 changes: 23 additions & 0 deletions src/objects/BatchedMesh.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 ) {

Expand Down
10 changes: 9 additions & 1 deletion src/renderers/WebGLRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 ) {

Expand Down
36 changes: 36 additions & 0 deletions src/renderers/webgl/WebGLBufferRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;

}

Expand Down
36 changes: 36 additions & 0 deletions src/renderers/webgl/WebGLIndexedBufferRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,49 @@ 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;
this.setIndex = setIndex;
this.render = render;
this.renderInstances = renderInstances;
this.renderMultiDraw = renderMultiDraw;
this.renderMultiDrawInstances = renderMultiDrawInstances;

}

Expand Down