diff --git a/examples/jsm/objects/BatchedMesh.js b/examples/jsm/objects/BatchedMesh.js index cfe742d1034780..4e80635577aa8a 100644 --- a/examples/jsm/objects/BatchedMesh.js +++ b/examples/jsm/objects/BatchedMesh.js @@ -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 @@ -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 ); } @@ -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 } ); @@ -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; @@ -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*/ ) { diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index 15ebd1c6434e2c..845e8c3fc61862 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -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 ); diff --git a/src/renderers/webgl/WebGLBufferRenderer.js b/src/renderers/webgl/WebGLBufferRenderer.js index 484298f6db9023..da8d8cdc9a3551 100644 --- a/src/renderers/webgl/WebGLBufferRenderer.js +++ b/src/renderers/webgl/WebGLBufferRenderer.js @@ -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; } diff --git a/src/renderers/webgl/WebGLIndexedBufferRenderer.js b/src/renderers/webgl/WebGLIndexedBufferRenderer.js index 7186c6797b2e89..7c9e92717c72a4 100644 --- a/src/renderers/webgl/WebGLIndexedBufferRenderer.js +++ b/src/renderers/webgl/WebGLIndexedBufferRenderer.js @@ -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; }