Skip to content

Commit

Permalink
WebGLRenderer: Add initial support for multi draw BatchedMesh (#27111)
Browse files Browse the repository at this point in the history
* Add support for multi draw

* Fix multidraw
  • Loading branch information
gkjohnson authored Nov 5, 2023
1 parent 6d7566e commit 0319a2a
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 3 deletions.
37 changes: 35 additions & 2 deletions examples/jsm/objects/BatchedMesh.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ class BatchedMesh extends Mesh {

this._geometryInitialized = false;
this._geometryCount = 0;
this._multiDrawCounts = null;
this._multiDrawStarts = null;
this._multiDrawCount = 0;

// Local matrix per geometry by using data texture
// @TODO: Support uniform parameter per geometry
Expand Down Expand Up @@ -240,6 +243,8 @@ class BatchedMesh extends Mesh {
geometry.setAttribute( ID_ATTR_NAME, new BufferAttribute( idArray, 1 ) );

this._geometryInitialized = true;
this._multiDrawCounts = new Int32Array( maxGeometryCount );
this._multiDrawStarts = new Int32Array( maxGeometryCount );

}

Expand Down Expand Up @@ -436,7 +441,7 @@ class BatchedMesh extends Mesh {
// add the reserved range and draw range objects
reservedRanges.push( reservedRange );
drawRanges.push( {
start: hasIndex ? reservedRange.indexStart * 3 : reservedRange.vertexStart * 3,
start: hasIndex ? reservedRange.indexStart : reservedRange.vertexStart,
count: - 1
} );

Expand Down Expand Up @@ -541,7 +546,7 @@ class BatchedMesh extends Mesh {
// set drawRange count
const drawRange = this._drawRanges[ id ];
const posAttr = geometry.getAttribute( 'position' );
drawRange.count = hasIndex ? srcIndex.count * 3 : posAttr.count * 3;
drawRange.count = hasIndex ? srcIndex.count : posAttr.count;

return id;

Expand Down Expand Up @@ -705,8 +710,36 @@ class BatchedMesh extends Mesh {

material.defines.BATCHING = true;

// the indexed version of the multi draw function requires specifying the start
// offset in bytes.
const index = _geometry.getIndex();
const bytesPerElement = index === null ? 1 : index.array.BYTES_PER_ELEMENT;

const visible = this._visible;
const multiDrawStarts = this._multiDrawStarts;
const multiDrawCounts = this._multiDrawCounts;
const drawRanges = this._drawRanges;

let count = 0;
for ( let i = 0, l = visible.length; i < l; i ++ ) {

if ( visible[ i ] ) {

const range = drawRanges[ i ];
multiDrawStarts[ count ] = range.start * bytesPerElement;
multiDrawCounts[ count ] = range.count;
count ++;

}

}

this._multiDrawCount = count;

// @TODO: Implement frustum culling for each geometry

// @TODO: Implement geometry sorting for transparent and opaque materials

}

onAfterRender( _renderer, _scene, _camera, _geometry, material/*, _group*/ ) {
Expand Down
6 changes: 5 additions & 1 deletion src/renderers/WebGLRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -896,7 +896,11 @@ class WebGLRenderer {

}

if ( object.isInstancedMesh ) {
if ( object.isBatchedMesh ) {

renderer.renderMultiDraw( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount );

} else if ( object.isInstancedMesh ) {

renderer.renderInstances( drawStart, drawCount, object.count );

Expand Down
26 changes: 26 additions & 0 deletions src/renderers/webgl/WebGLBufferRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,37 @@ function WebGLBufferRenderer( gl, extensions, info, capabilities ) {

}

function renderMultiDraw( starts, counts, drawCount ) {

if ( drawCount === 0 ) return;

const extension = extensions.get( 'WEBGL_multi_draw' );
if ( extension === null ) {

console.error( 'THREE.WebGLBufferRenderer: using THREE.BatchedMesh but hardware does not support extension WEBGL_multi_draw.' );
return;

}

extension.multiDrawArraysWEBGL( mode, starts, 0, counts, 0, drawCount );

let elementCount = 0;
for ( let i = 0; i < drawCount; i ++ ) {

elementCount += counts[ i ];

}

info.update( elementCount, mode, 1 );

}

//

this.setMode = setMode;
this.render = render;
this.renderInstances = renderInstances;
this.renderMultiDraw = renderMultiDraw;

}

Expand Down
26 changes: 26 additions & 0 deletions src/renderers/webgl/WebGLIndexedBufferRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,38 @@ function WebGLIndexedBufferRenderer( gl, extensions, info, capabilities ) {

}

function renderMultiDraw( starts, counts, drawCount ) {

if ( drawCount === 0 ) return;

const extension = extensions.get( 'WEBGL_multi_draw' );
if ( extension === null ) {

console.error( 'THREE.WebGLBufferRenderer: using THREE.BatchedMesh but hardware does not support extension WEBGL_multi_draw.' );
return;

}

extension.multiDrawElementsWEBGL( mode, counts, 0, type, starts, 0, drawCount );

let elementCount = 0;
for ( let i = 0; i < drawCount; i ++ ) {

elementCount += counts[ i ];

}

info.update( elementCount, mode, 1 );

}

//

this.setMode = setMode;
this.setIndex = setIndex;
this.render = render;
this.renderInstances = renderInstances;
this.renderMultiDraw = renderMultiDraw;

}

Expand Down

0 comments on commit 0319a2a

Please sign in to comment.