From c7a8eb101d355956ceeab4d9a7de5ddc979059d9 Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Fri, 3 Nov 2023 21:02:05 +0900 Subject: [PATCH 01/13] Add support for multi draw --- examples/jsm/objects/BatchedMesh.js | 27 +++++++++++++++++++ src/renderers/WebGLRenderer.js | 6 ++++- src/renderers/webgl/WebGLBufferRenderer.js | 26 ++++++++++++++++++ .../webgl/WebGLIndexedBufferRenderer.js | 26 ++++++++++++++++++ 4 files changed, 84 insertions(+), 1 deletion(-) diff --git a/examples/jsm/objects/BatchedMesh.js b/examples/jsm/objects/BatchedMesh.js index cfe742d1034780..d582930c384e9d 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 ); } @@ -705,8 +710,30 @@ class BatchedMesh extends Mesh { material.defines.BATCHING = true; + const visible = this._visible; + const multiDrawCounts = this._multiDrawCounts; + const multiDrawStarts = this._multiDrawStarts; + 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; + 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..8bcac7592035b2 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; } From c453f4b08a009dd562a3b80839b182fba3a82d85 Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Fri, 3 Nov 2023 22:03:41 +0900 Subject: [PATCH 02/13] Fix multidraw --- examples/jsm/objects/BatchedMesh.js | 14 ++++++++++---- src/renderers/WebGLRenderer.js | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/examples/jsm/objects/BatchedMesh.js b/examples/jsm/objects/BatchedMesh.js index d582930c384e9d..4e80635577aa8a 100644 --- a/examples/jsm/objects/BatchedMesh.js +++ b/examples/jsm/objects/BatchedMesh.js @@ -441,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 } ); @@ -546,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; @@ -710,17 +710,23 @@ 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 multiDrawCounts = this._multiDrawCounts; 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; + multiDrawStarts[ count ] = range.start * bytesPerElement; multiDrawCounts[ count ] = range.count; count ++; diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index 8bcac7592035b2..845e8c3fc61862 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -898,7 +898,7 @@ class WebGLRenderer { if ( object.isBatchedMesh ) { - renderer.renderMultiDraw( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount ) + renderer.renderMultiDraw( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount ); } else if ( object.isInstancedMesh ) { From aa19ad661bbfc08c37b09e9917c2ccdc67465396 Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Sun, 5 Nov 2023 11:53:57 +0900 Subject: [PATCH 03/13] Add batching material properties --- src/renderers/WebGLRenderer.js | 9 +++++++++ src/renderers/webgl/WebGLProgram.js | 1 + src/renderers/webgl/WebGLPrograms.js | 4 ++++ 3 files changed, 14 insertions(+) diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index 845e8c3fc61862..73f5b58c2a79a6 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -1719,6 +1719,7 @@ class WebGLRenderer { const materialProperties = properties.get( material ); materialProperties.outputColorSpace = parameters.outputColorSpace; + materialProperties.batching = parameters.batching; materialProperties.instancing = parameters.instancing; materialProperties.instancingColor = parameters.instancingColor; materialProperties.skinning = parameters.skinning; @@ -1799,6 +1800,14 @@ class WebGLRenderer { needsProgramChange = true; + } else if ( object.isBatchedMesh && materialProperties.batching === false ) { + + needsProgramChange = true; + + } else if ( ! object.isBatchedMesh && materialProperties.batching === true ) { + + needsProgramChange = true; + } else if ( object.isInstancedMesh && materialProperties.instancing === false ) { needsProgramChange = true; diff --git a/src/renderers/webgl/WebGLProgram.js b/src/renderers/webgl/WebGLProgram.js index 42003540b313e8..0f04631cd656b8 100644 --- a/src/renderers/webgl/WebGLProgram.js +++ b/src/renderers/webgl/WebGLProgram.js @@ -503,6 +503,7 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) { customDefines, + parameters.batching ? '#define USE_BATCHING' : '', parameters.instancing ? '#define USE_INSTANCING' : '', parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '', diff --git a/src/renderers/webgl/WebGLPrograms.js b/src/renderers/webgl/WebGLPrograms.js index af1826eaf4a748..4adbdc01988155 100644 --- a/src/renderers/webgl/WebGLPrograms.js +++ b/src/renderers/webgl/WebGLPrograms.js @@ -108,6 +108,7 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities const currentRenderTarget = renderer.getRenderTarget(); const IS_INSTANCEDMESH = object.isInstancedMesh === true; + const IS_BATCHEDMESH = object.isBatchedMesh === true; const HAS_MAP = !! material.map; const HAS_MATCAP = !! material.matcap; @@ -193,6 +194,7 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities precision: precision, + batching: IS_BATCHEDMESH, instancing: IS_INSTANCEDMESH, instancingColor: IS_INSTANCEDMESH && object.instanceColor !== null, @@ -503,6 +505,8 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities _programLayers.enable( 17 ); if ( parameters.alphaHash ) _programLayers.enable( 18 ); + if ( parameters.batching ) + _programLayers.enable( 19 ); array.push( _programLayers.mask ); _programLayers.disableAll(); From 816aa6f96c065f05b4d2b46519024b57b232f86b Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Sun, 5 Nov 2023 11:54:07 +0900 Subject: [PATCH 04/13] Adjust batching define --- examples/jsm/objects/BatchedMesh.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/jsm/objects/BatchedMesh.js b/examples/jsm/objects/BatchedMesh.js index 4e80635577aa8a..a6e50e922f03b4 100644 --- a/examples/jsm/objects/BatchedMesh.js +++ b/examples/jsm/objects/BatchedMesh.js @@ -20,7 +20,7 @@ const _zeroScaleMatrix = new Matrix4().set( // Custom shaders const batchingParsVertex = /* glsl */` -#ifdef BATCHING +#ifdef USE_BATCHING attribute float ${ ID_ATTR_NAME }; uniform highp sampler2D batchingTexture; mat4 getBatchingMatrix( const in float i ) { @@ -40,13 +40,13 @@ const batchingParsVertex = /* glsl */` `; const batchingbaseVertex = /* glsl */` -#ifdef BATCHING +#ifdef USE_BATCHING mat4 batchingMatrix = getBatchingMatrix( ${ ID_ATTR_NAME } ); #endif `; const batchingnormalVertex = /* glsl */` -#ifdef BATCHING +#ifdef USE_BATCHING objectNormal = vec4( batchingMatrix * vec4( objectNormal, 0.0 ) ).xyz; #ifdef USE_TANGENT objectTangent = vec4( batchingMatrix * vec4( objectTangent, 0.0 ) ).xyz; @@ -55,7 +55,7 @@ const batchingnormalVertex = /* glsl */` `; const batchingVertex = /* glsl */` -#ifdef BATCHING +#ifdef USE_BATCHING transformed = ( batchingMatrix * vec4( transformed, 1.0 ) ).xyz; #endif `; From 21620b7c21fb379b858c8a8e25beeff7bb8e0d25 Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Sun, 5 Nov 2023 12:05:25 +0900 Subject: [PATCH 05/13] Move normal shaders --- examples/jsm/objects/BatchedMesh.js | 14 -------------- .../ShaderChunk/defaultnormal_vertex.glsl.js | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/examples/jsm/objects/BatchedMesh.js b/examples/jsm/objects/BatchedMesh.js index a6e50e922f03b4..5ca1c34674c2fc 100644 --- a/examples/jsm/objects/BatchedMesh.js +++ b/examples/jsm/objects/BatchedMesh.js @@ -45,15 +45,6 @@ const batchingbaseVertex = /* glsl */` #endif `; -const batchingnormalVertex = /* glsl */` -#ifdef USE_BATCHING - objectNormal = vec4( batchingMatrix * vec4( objectNormal, 0.0 ) ).xyz; - #ifdef USE_TANGENT - objectTangent = vec4( batchingMatrix * vec4( objectTangent, 0.0 ) ).xyz; - #endif -#endif -`; - const batchingVertex = /* glsl */` #ifdef USE_BATCHING transformed = ( batchingMatrix * vec4( transformed, 1.0 ) ).xyz; @@ -176,11 +167,6 @@ class BatchedMesh extends Mesh { '#include \n' + batchingbaseVertex ) - .replace( - '#include ', - '#include \n' - + batchingnormalVertex - ) .replace( '#include ', '#include \n' diff --git a/src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl.js b/src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl.js index 518bb39a16608c..3c9dd8fb8ec91e 100644 --- a/src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl.js +++ b/src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl.js @@ -1,4 +1,23 @@ export default /* glsl */` + +#ifdef USE_BATCHING + + // this is in lieu of a per-instance normal-matrix + // shear transforms in the instance matrix are not supported + + mat3 bm = mat3( batchingMatrix ); + objectNormal /= vec3( dot( bm[ 0 ], bm[ 0 ] ), dot( bm[ 1 ], bm[ 1 ] ), dot( bm[ 2 ], bm[ 2 ] ) ); + objectNormal = bm * objectNormal; + + #ifdef USE_TANGENT + + objectTangent /= vec3( dot( bm[ 0 ], bm[ 0 ] ), dot( bm[ 1 ], bm[ 1 ] ), dot( bm[ 2 ], bm[ 2 ] ) ); + objectTangent = bm * objectTangent; + + #endif + +#endif + vec3 transformedNormal = objectNormal; #ifdef USE_INSTANCING From a3d2fd017ece28803ede7b56d84d9f286bdeb9fc Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Sun, 5 Nov 2023 12:08:38 +0900 Subject: [PATCH 06/13] Move vertex transform shadres --- examples/jsm/objects/BatchedMesh.js | 11 ----------- .../shaders/ShaderChunk/project_vertex.glsl.js | 6 ++++++ .../shaders/ShaderChunk/worldpos_vertex.glsl.js | 6 ++++++ 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/examples/jsm/objects/BatchedMesh.js b/examples/jsm/objects/BatchedMesh.js index 5ca1c34674c2fc..cb3bef99e904dd 100644 --- a/examples/jsm/objects/BatchedMesh.js +++ b/examples/jsm/objects/BatchedMesh.js @@ -45,12 +45,6 @@ const batchingbaseVertex = /* glsl */` #endif `; -const batchingVertex = /* glsl */` -#ifdef USE_BATCHING - transformed = ( batchingMatrix * vec4( transformed, 1.0 ) ).xyz; -#endif -`; - // @TODO: SkinnedMesh support? // @TODO: Future work if needed. Move into the core. Can be optimized more with WEBGL_multi_draw. @@ -166,11 +160,6 @@ class BatchedMesh extends Mesh { '#include ', '#include \n' + batchingbaseVertex - ) - .replace( - '#include ', - '#include \n' - + batchingVertex ); for ( const uniformName in customUniforms ) { diff --git a/src/renderers/shaders/ShaderChunk/project_vertex.glsl.js b/src/renderers/shaders/ShaderChunk/project_vertex.glsl.js index 0c28ed857c5986..c310db1b74a572 100644 --- a/src/renderers/shaders/ShaderChunk/project_vertex.glsl.js +++ b/src/renderers/shaders/ShaderChunk/project_vertex.glsl.js @@ -1,6 +1,12 @@ export default /* glsl */` vec4 mvPosition = vec4( transformed, 1.0 ); +#ifdef USE_BATCHING + + mvPosition = batchingMatrix * mvPosition; + +#endif + #ifdef USE_INSTANCING mvPosition = instanceMatrix * mvPosition; diff --git a/src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl.js b/src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl.js index 197295ffd0a8d5..b4eefdf802cc2c 100644 --- a/src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl.js +++ b/src/renderers/shaders/ShaderChunk/worldpos_vertex.glsl.js @@ -3,6 +3,12 @@ export default /* glsl */` vec4 worldPosition = vec4( transformed, 1.0 ); + #ifdef USE_BATCHING + + worldPosition = batchingMatrix * worldPosition; + + #endif + #ifdef USE_INSTANCING worldPosition = instanceMatrix * worldPosition; From 9cc73b426ce379b92ae91eec0843ec4aadd9340e Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Sun, 5 Nov 2023 12:15:51 +0900 Subject: [PATCH 07/13] Move batching pars --- examples/jsm/objects/BatchedMesh.js | 25 ------------------- src/renderers/shaders/ShaderChunk.js | 2 ++ .../ShaderChunk/batching_pars_vertex.glsl.js | 19 ++++++++++++++ .../shaders/ShaderLib/distanceRGBA.glsl.js | 1 + .../shaders/ShaderLib/meshbasic.glsl.js | 1 + .../shaders/ShaderLib/meshlambert.glsl.js | 1 + .../shaders/ShaderLib/meshmatcap.glsl.js | 1 + .../shaders/ShaderLib/meshnormal.glsl.js | 1 + .../shaders/ShaderLib/meshphong.glsl.js | 1 + .../shaders/ShaderLib/meshphysical.glsl.js | 1 + .../shaders/ShaderLib/meshtoon.glsl.js | 1 + .../shaders/ShaderLib/shadow.glsl.js | 1 + 12 files changed, 30 insertions(+), 25 deletions(-) create mode 100644 src/renderers/shaders/ShaderChunk/batching_pars_vertex.glsl.js diff --git a/examples/jsm/objects/BatchedMesh.js b/examples/jsm/objects/BatchedMesh.js index cb3bef99e904dd..e59e7deb7aa661 100644 --- a/examples/jsm/objects/BatchedMesh.js +++ b/examples/jsm/objects/BatchedMesh.js @@ -19,26 +19,6 @@ const _zeroScaleMatrix = new Matrix4().set( ); // Custom shaders -const batchingParsVertex = /* glsl */` -#ifdef USE_BATCHING - attribute float ${ ID_ATTR_NAME }; - uniform highp sampler2D batchingTexture; - mat4 getBatchingMatrix( const in float i ) { - - int size = textureSize( batchingTexture, 0 ).x; - int j = int( i ) * 4; - int x = j % size; - int y = j / size; - vec4 v1 = texelFetch( batchingTexture, ivec2( x, y ), 0 ); - vec4 v2 = texelFetch( batchingTexture, ivec2( x + 1, y ), 0 ); - vec4 v3 = texelFetch( batchingTexture, ivec2( x + 2, y ), 0 ); - vec4 v4 = texelFetch( batchingTexture, ivec2( x + 3, y ), 0 ); - return mat4( v1, v2, v3, v4 ); - - } -#endif -`; - const batchingbaseVertex = /* glsl */` #ifdef USE_BATCHING mat4 batchingMatrix = getBatchingMatrix( ${ ID_ATTR_NAME } ); @@ -151,11 +131,6 @@ class BatchedMesh extends Mesh { // Is this replacement stable across any materials? parameters.vertexShader = parameters.vertexShader - .replace( - '#include ', - '#include \n' - + batchingParsVertex - ) .replace( '#include ', '#include \n' diff --git a/src/renderers/shaders/ShaderChunk.js b/src/renderers/shaders/ShaderChunk.js index eb6f7e2354c1a5..78d1fa0844268e 100644 --- a/src/renderers/shaders/ShaderChunk.js +++ b/src/renderers/shaders/ShaderChunk.js @@ -6,6 +6,7 @@ import alphatest_fragment from './ShaderChunk/alphatest_fragment.glsl.js'; import alphatest_pars_fragment from './ShaderChunk/alphatest_pars_fragment.glsl.js'; import aomap_fragment from './ShaderChunk/aomap_fragment.glsl.js'; import aomap_pars_fragment from './ShaderChunk/aomap_pars_fragment.glsl.js'; +import batching_pars_vertex from './ShaderChunk/batching_pars_vertex.glsl.js'; import begin_vertex from './ShaderChunk/begin_vertex.glsl.js'; import beginnormal_vertex from './ShaderChunk/beginnormal_vertex.glsl.js'; import bsdfs from './ShaderChunk/bsdfs.glsl.js'; @@ -131,6 +132,7 @@ export const ShaderChunk = { alphatest_pars_fragment: alphatest_pars_fragment, aomap_fragment: aomap_fragment, aomap_pars_fragment: aomap_pars_fragment, + batching_pars_vertex: batching_pars_vertex, begin_vertex: begin_vertex, beginnormal_vertex: beginnormal_vertex, bsdfs: bsdfs, diff --git a/src/renderers/shaders/ShaderChunk/batching_pars_vertex.glsl.js b/src/renderers/shaders/ShaderChunk/batching_pars_vertex.glsl.js new file mode 100644 index 00000000000000..f165c3d803a9d8 --- /dev/null +++ b/src/renderers/shaders/ShaderChunk/batching_pars_vertex.glsl.js @@ -0,0 +1,19 @@ +export default /* glsl */` +#ifdef USE_BATCHING + attribute float _batch_id_; + uniform highp sampler2D batchingTexture; + mat4 getBatchingMatrix( const in float i ) { + + int size = textureSize( batchingTexture, 0 ).x; + int j = int( i ) * 4; + int x = j % size; + int y = j / size; + vec4 v1 = texelFetch( batchingTexture, ivec2( x, y ), 0 ); + vec4 v2 = texelFetch( batchingTexture, ivec2( x + 1, y ), 0 ); + vec4 v3 = texelFetch( batchingTexture, ivec2( x + 2, y ), 0 ); + vec4 v4 = texelFetch( batchingTexture, ivec2( x + 3, y ), 0 ); + return mat4( v1, v2, v3, v4 ); + + } +#endif +`; diff --git a/src/renderers/shaders/ShaderLib/distanceRGBA.glsl.js b/src/renderers/shaders/ShaderLib/distanceRGBA.glsl.js index a69607aaeb6275..d3622cbc557b83 100644 --- a/src/renderers/shaders/ShaderLib/distanceRGBA.glsl.js +++ b/src/renderers/shaders/ShaderLib/distanceRGBA.glsl.js @@ -4,6 +4,7 @@ export const vertex = /* glsl */` varying vec3 vWorldPosition; #include +#include #include #include #include diff --git a/src/renderers/shaders/ShaderLib/meshbasic.glsl.js b/src/renderers/shaders/ShaderLib/meshbasic.glsl.js index ec44579c18381f..052c2d0d8de8d9 100644 --- a/src/renderers/shaders/ShaderLib/meshbasic.glsl.js +++ b/src/renderers/shaders/ShaderLib/meshbasic.glsl.js @@ -1,5 +1,6 @@ export const vertex = /* glsl */` #include +#include #include #include #include diff --git a/src/renderers/shaders/ShaderLib/meshlambert.glsl.js b/src/renderers/shaders/ShaderLib/meshlambert.glsl.js index e8e2f28b7295df..3fff7689b3601b 100644 --- a/src/renderers/shaders/ShaderLib/meshlambert.glsl.js +++ b/src/renderers/shaders/ShaderLib/meshlambert.glsl.js @@ -4,6 +4,7 @@ export const vertex = /* glsl */` varying vec3 vViewPosition; #include +#include #include #include #include diff --git a/src/renderers/shaders/ShaderLib/meshmatcap.glsl.js b/src/renderers/shaders/ShaderLib/meshmatcap.glsl.js index d1018bbc985d30..e4fc33876585a0 100644 --- a/src/renderers/shaders/ShaderLib/meshmatcap.glsl.js +++ b/src/renderers/shaders/ShaderLib/meshmatcap.glsl.js @@ -4,6 +4,7 @@ export const vertex = /* glsl */` varying vec3 vViewPosition; #include +#include #include #include #include diff --git a/src/renderers/shaders/ShaderLib/meshnormal.glsl.js b/src/renderers/shaders/ShaderLib/meshnormal.glsl.js index 769e54fefc68a9..32d5eae0ae270e 100644 --- a/src/renderers/shaders/ShaderLib/meshnormal.glsl.js +++ b/src/renderers/shaders/ShaderLib/meshnormal.glsl.js @@ -8,6 +8,7 @@ export const vertex = /* glsl */` #endif #include +#include #include #include #include diff --git a/src/renderers/shaders/ShaderLib/meshphong.glsl.js b/src/renderers/shaders/ShaderLib/meshphong.glsl.js index 3248b1aa87d545..9c412694d395f4 100644 --- a/src/renderers/shaders/ShaderLib/meshphong.glsl.js +++ b/src/renderers/shaders/ShaderLib/meshphong.glsl.js @@ -4,6 +4,7 @@ export const vertex = /* glsl */` varying vec3 vViewPosition; #include +#include #include #include #include diff --git a/src/renderers/shaders/ShaderLib/meshphysical.glsl.js b/src/renderers/shaders/ShaderLib/meshphysical.glsl.js index 6c9a61d7886e62..241e5fc09e3077 100644 --- a/src/renderers/shaders/ShaderLib/meshphysical.glsl.js +++ b/src/renderers/shaders/ShaderLib/meshphysical.glsl.js @@ -10,6 +10,7 @@ varying vec3 vViewPosition; #endif #include +#include #include #include #include diff --git a/src/renderers/shaders/ShaderLib/meshtoon.glsl.js b/src/renderers/shaders/ShaderLib/meshtoon.glsl.js index 458b406743132f..de46e55b8d5ae0 100644 --- a/src/renderers/shaders/ShaderLib/meshtoon.glsl.js +++ b/src/renderers/shaders/ShaderLib/meshtoon.glsl.js @@ -4,6 +4,7 @@ export const vertex = /* glsl */` varying vec3 vViewPosition; #include +#include #include #include #include diff --git a/src/renderers/shaders/ShaderLib/shadow.glsl.js b/src/renderers/shaders/ShaderLib/shadow.glsl.js index ad2405c4d065a3..b6a610ac566929 100644 --- a/src/renderers/shaders/ShaderLib/shadow.glsl.js +++ b/src/renderers/shaders/ShaderLib/shadow.glsl.js @@ -1,5 +1,6 @@ export const vertex = /* glsl */` #include +#include #include #include #include From 7f99d8371567b796e9e4c717aac4019d76957440 Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Sun, 5 Nov 2023 12:23:25 +0900 Subject: [PATCH 08/13] Move batching matrix fetch --- examples/jsm/objects/BatchedMesh.js | 15 --------------- .../ShaderChunk/defaultnormal_vertex.glsl.js | 1 + src/renderers/shaders/ShaderLib/depth.glsl.js | 1 + 3 files changed, 2 insertions(+), 15 deletions(-) diff --git a/examples/jsm/objects/BatchedMesh.js b/examples/jsm/objects/BatchedMesh.js index e59e7deb7aa661..2b943d3362cdbb 100644 --- a/examples/jsm/objects/BatchedMesh.js +++ b/examples/jsm/objects/BatchedMesh.js @@ -18,13 +18,6 @@ const _zeroScaleMatrix = new Matrix4().set( 0, 0, 0, 1, ); -// Custom shaders -const batchingbaseVertex = /* glsl */` -#ifdef USE_BATCHING - mat4 batchingMatrix = getBatchingMatrix( ${ ID_ATTR_NAME } ); -#endif -`; - // @TODO: SkinnedMesh support? // @TODO: Future work if needed. Move into the core. Can be optimized more with WEBGL_multi_draw. @@ -129,14 +122,6 @@ class BatchedMesh extends Mesh { material.onBeforeCompile = function onBeforeCompile( parameters, renderer ) { - // Is this replacement stable across any materials? - parameters.vertexShader = parameters.vertexShader - .replace( - '#include ', - '#include \n' - + batchingbaseVertex - ); - for ( const uniformName in customUniforms ) { parameters.uniforms[ uniformName ] = customUniforms[ uniformName ]; diff --git a/src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl.js b/src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl.js index 3c9dd8fb8ec91e..f32fdad49f9b8a 100644 --- a/src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl.js +++ b/src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl.js @@ -5,6 +5,7 @@ export default /* glsl */` // this is in lieu of a per-instance normal-matrix // shear transforms in the instance matrix are not supported + mat4 batchingMatrix = getBatchingMatrix( _batch_id_ ); mat3 bm = mat3( batchingMatrix ); objectNormal /= vec3( dot( bm[ 0 ], bm[ 0 ] ), dot( bm[ 1 ], bm[ 1 ] ), dot( bm[ 2 ], bm[ 2 ] ) ); objectNormal = bm * objectNormal; diff --git a/src/renderers/shaders/ShaderLib/depth.glsl.js b/src/renderers/shaders/ShaderLib/depth.glsl.js index bfddb420deb414..8df7a4d6b254ca 100644 --- a/src/renderers/shaders/ShaderLib/depth.glsl.js +++ b/src/renderers/shaders/ShaderLib/depth.glsl.js @@ -1,5 +1,6 @@ export const vertex = /* glsl */` #include +#include #include #include #include From f5b394146f9242c0399651c28c6058d37a1d73ac Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Sun, 5 Nov 2023 12:25:20 +0900 Subject: [PATCH 09/13] Switch _batch_id_ to batchId --- examples/jsm/objects/BatchedMesh.js | 2 +- src/renderers/shaders/ShaderChunk/batching_pars_vertex.glsl.js | 2 +- src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/jsm/objects/BatchedMesh.js b/examples/jsm/objects/BatchedMesh.js index 2b943d3362cdbb..e7b1514057112d 100644 --- a/examples/jsm/objects/BatchedMesh.js +++ b/examples/jsm/objects/BatchedMesh.js @@ -9,7 +9,7 @@ import { RGBAFormat } from 'three'; -const ID_ATTR_NAME = '_batch_id_'; +const ID_ATTR_NAME = 'batchId'; const _identityMatrix = new Matrix4(); const _zeroScaleMatrix = new Matrix4().set( 0, 0, 0, 0, diff --git a/src/renderers/shaders/ShaderChunk/batching_pars_vertex.glsl.js b/src/renderers/shaders/ShaderChunk/batching_pars_vertex.glsl.js index f165c3d803a9d8..fb602a0f7d8804 100644 --- a/src/renderers/shaders/ShaderChunk/batching_pars_vertex.glsl.js +++ b/src/renderers/shaders/ShaderChunk/batching_pars_vertex.glsl.js @@ -1,6 +1,6 @@ export default /* glsl */` #ifdef USE_BATCHING - attribute float _batch_id_; + attribute float batchId; uniform highp sampler2D batchingTexture; mat4 getBatchingMatrix( const in float i ) { diff --git a/src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl.js b/src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl.js index f32fdad49f9b8a..5ba3202d7da061 100644 --- a/src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl.js +++ b/src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl.js @@ -5,7 +5,7 @@ export default /* glsl */` // this is in lieu of a per-instance normal-matrix // shear transforms in the instance matrix are not supported - mat4 batchingMatrix = getBatchingMatrix( _batch_id_ ); + mat4 batchingMatrix = getBatchingMatrix( batchId ); mat3 bm = mat3( batchingMatrix ); objectNormal /= vec3( dot( bm[ 0 ], bm[ 0 ] ), dot( bm[ 1 ], bm[ 1 ] ), dot( bm[ 2 ], bm[ 2 ] ) ); objectNormal = bm * objectNormal; From efef965d6828e048406918fdf4ba22529db3c117 Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Sun, 5 Nov 2023 12:31:29 +0900 Subject: [PATCH 10/13] Remove custom shader callback --- examples/jsm/objects/BatchedMesh.js | 36 ++--------------------------- src/renderers/WebGLRenderer.js | 7 ++++++ 2 files changed, 9 insertions(+), 34 deletions(-) diff --git a/examples/jsm/objects/BatchedMesh.js b/examples/jsm/objects/BatchedMesh.js index e7b1514057112d..34656fe3eebc21 100644 --- a/examples/jsm/objects/BatchedMesh.js +++ b/examples/jsm/objects/BatchedMesh.js @@ -89,7 +89,6 @@ class BatchedMesh extends Mesh { }; this._initMatricesTexture(); - this._initShader(); } @@ -114,29 +113,6 @@ class BatchedMesh extends Mesh { } - _initShader() { - - const material = this.material; - const currentOnBeforeCompile = material.onBeforeCompile; - const customUniforms = this._customUniforms; - - material.onBeforeCompile = function onBeforeCompile( parameters, renderer ) { - - for ( const uniformName in customUniforms ) { - - parameters.uniforms[ uniformName ] = customUniforms[ uniformName ]; - - } - - currentOnBeforeCompile.call( this, parameters, renderer ); - - }; - - material.defines = material.defines || {}; - material.defines.BATCHING = false; - - } - _initializeGeometry( reference ) { // @TODO: geometry.groups support? @@ -641,13 +617,11 @@ class BatchedMesh extends Mesh { } - onBeforeRender( _renderer, _scene, _camera, _geometry, material/*, _group*/ ) { - - material.defines.BATCHING = true; + onBeforeRender( _renderer, _scene, _camera, geometry ) { // the indexed version of the multi draw function requires specifying the start // offset in bytes. - const index = _geometry.getIndex(); + const index = geometry.getIndex(); const bytesPerElement = index === null ? 1 : index.array.BYTES_PER_ELEMENT; const visible = this._visible; @@ -677,12 +651,6 @@ class BatchedMesh extends Mesh { } - onAfterRender( _renderer, _scene, _camera, _geometry, material/*, _group*/ ) { - - material.defines.BATCHING = false; - - } - } export { BatchedMesh }; diff --git a/src/renderers/WebGLRenderer.js b/src/renderers/WebGLRenderer.js index 73f5b58c2a79a6..7621c4325d524c 100644 --- a/src/renderers/WebGLRenderer.js +++ b/src/renderers/WebGLRenderer.js @@ -1996,6 +1996,13 @@ class WebGLRenderer { } + if ( object.isBatchedMesh ) { + + p_uniforms.setOptional( _gl, object, 'batchingTexture' ); + p_uniforms.setValue( _gl, 'batchingTexture', object._matricesTexture, textures ); + + } + const morphAttributes = geometry.morphAttributes; if ( morphAttributes.position !== undefined || morphAttributes.normal !== undefined || ( morphAttributes.color !== undefined && capabilities.isWebGL2 === true ) ) { From 364e8f733f59aa219ec77f2afc22d061c97dc984 Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Sun, 5 Nov 2023 16:57:10 +0900 Subject: [PATCH 11/13] Remove "matrices" array --- examples/jsm/objects/BatchedMesh.js | 47 ++++++++--------------------- 1 file changed, 13 insertions(+), 34 deletions(-) diff --git a/examples/jsm/objects/BatchedMesh.js b/examples/jsm/objects/BatchedMesh.js index 34656fe3eebc21..a980382e826181 100644 --- a/examples/jsm/objects/BatchedMesh.js +++ b/examples/jsm/objects/BatchedMesh.js @@ -333,7 +333,6 @@ class BatchedMesh extends Mesh { const visible = this._visible; const active = this._active; const matricesTexture = this._matricesTexture; - const matrices = this._matrices; const matricesArray = this._matricesTexture.image.data; // push new visibility states @@ -345,7 +344,6 @@ class BatchedMesh extends Mesh { this._geometryCount ++; // initialize matrix information - matrices.push( new Matrix4() ); _identityMatrix.toArray( matricesArray, geometryId * 16 ); matricesTexture.needsUpdate = true; @@ -495,25 +493,18 @@ class BatchedMesh extends Mesh { // @TODO: Map geometryId to index of the arrays because // optimize() can make geometryId mismatch the index - const visible = this._visible; const active = this._active; const matricesTexture = this._matricesTexture; - const matrices = this._matrices; const matricesArray = this._matricesTexture.image.data; - if ( geometryId >= matrices.length || active[ geometryId ] === false ) { + const geometryCount = this._geometryCount; + if ( geometryId >= geometryCount || active[ geometryId ] === false ) { return this; } - if ( visible[ geometryId ] === true ) { - - matrix.toArray( matricesArray, geometryId * 16 ); - matricesTexture.needsUpdate = true; - - } - - matrices[ geometryId ].copy( matrix ); + matrix.toArray( matricesArray, geometryId * 16 ); + matricesTexture.needsUpdate = true; return this; @@ -521,15 +512,16 @@ class BatchedMesh extends Mesh { getMatrixAt( geometryId, matrix ) { - const matrices = this._matrices; const active = this._active; - if ( geometryId >= matrices.length || active[ geometryId ] === false ) { + const matricesArray = this._matricesTexture.image.data; + const geometryCount = this._geometryCount; + if ( geometryId >= geometryCount || active[ geometryId ] === false ) { - return matrix; + return null; } - return matrix.copy( matrices[ geometryId ] ); + return matrix.fromArray( matricesArray, geometryId * 16 ); } @@ -537,14 +529,12 @@ class BatchedMesh extends Mesh { const visible = this._visible; const active = this._active; - const matricesTexture = this._matricesTexture; - const matrices = this._matrices; - const matricesArray = this._matricesTexture.image.data; + const geometryCount = this._geometryCount; // if the geometry is out of range, not active, or visibility state // does not change then return early if ( - geometryId >= visible.length || + geometryId >= geometryCount || active[ geometryId ] === false || visible[ geometryId ] === value ) { @@ -553,18 +543,6 @@ class BatchedMesh extends Mesh { } - // scale the matrix to zero if it's hidden - if ( value === true ) { - - matrices[ geometryId ].toArray( matricesArray, geometryId * 16 ); - - } else { - - _zeroScaleMatrix.toArray( matricesArray, geometryId * 16 ); - - } - - matricesTexture.needsUpdate = true; visible[ geometryId ] = value; return this; @@ -574,9 +552,10 @@ class BatchedMesh extends Mesh { const visible = this._visible; const active = this._active; + const geometryCount = this._geometryCount; // return early if the geometry is out of range or not active - if ( geometryId >= visible.length || active[ geometryId ] === false ) { + if ( geometryId >= geometryCount || active[ geometryId ] === false ) { return false; From 816fedab3805fbf2ba978db383eb832806a92ae2 Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Sun, 5 Nov 2023 17:01:18 +0900 Subject: [PATCH 12/13] Remove unused custom uniforms --- examples/jsm/objects/BatchedMesh.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/examples/jsm/objects/BatchedMesh.js b/examples/jsm/objects/BatchedMesh.js index 34656fe3eebc21..7bde9f6e9967e2 100644 --- a/examples/jsm/objects/BatchedMesh.js +++ b/examples/jsm/objects/BatchedMesh.js @@ -84,10 +84,6 @@ class BatchedMesh extends Mesh { // @TODO: Calculate the entire binding box and make frustumCulled true this.frustumCulled = false; - this._customUniforms = { - batchingTexture: { value: null } - }; - this._initMatricesTexture(); } @@ -109,7 +105,6 @@ class BatchedMesh extends Mesh { const matricesTexture = new DataTexture( matricesArray, size, size, RGBAFormat, FloatType ); this._matricesTexture = matricesTexture; - this._customUniforms.batchingTexture.value = this._matricesTexture; } From 3d6bc9ef46b4ffce9fa27b863978655fa38dcf1b Mon Sep 17 00:00:00 2001 From: Garrett Johnson Date: Sun, 5 Nov 2023 21:05:50 +0900 Subject: [PATCH 13/13] Remove unneeded field --- examples/jsm/objects/BatchedMesh.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/examples/jsm/objects/BatchedMesh.js b/examples/jsm/objects/BatchedMesh.js index 3ad309d8650b6c..9e01d7118a5184 100644 --- a/examples/jsm/objects/BatchedMesh.js +++ b/examples/jsm/objects/BatchedMesh.js @@ -20,6 +20,10 @@ const _zeroScaleMatrix = new Matrix4().set( // @TODO: SkinnedMesh support? // @TODO: Future work if needed. Move into the core. Can be optimized more with WEBGL_multi_draw. +// @TODO: geometry.groups support? +// @TODO: geometry.drawRange support? +// @TODO: geometry.morphAttributes support? +// @TODO: Support uniform parameter per geometry // copies data from attribute "src" into "target" starting at "targetOffset" function copyAttributeData( src, target, targetOffset = 0 ) { @@ -76,9 +80,6 @@ class BatchedMesh extends Mesh { this._multiDrawCount = 0; // Local matrix per geometry by using data texture - // @TODO: Support uniform parameter per geometry - - this._matrices = []; this._matricesTexture = null; // @TODO: Calculate the entire binding box and make frustumCulled true @@ -110,10 +111,6 @@ class BatchedMesh extends Mesh { _initializeGeometry( reference ) { - // @TODO: geometry.groups support? - // @TODO: geometry.drawRange support? - // @TODO: geometry.morphAttributes support? - const geometry = this.geometry; const maxVertexCount = this._maxVertexCount; const maxGeometryCount = this._maxGeometryCount;