|
@@ -1,7 +1,7 @@
|
|
|
import { BufferAttribute } from '../core/BufferAttribute.js';
|
|
|
import { BufferGeometry } from '../core/BufferGeometry.js';
|
|
|
import { DataTexture } from '../textures/DataTexture.js';
|
|
|
-import { FloatType, RedIntegerFormat, UnsignedIntType } from '../constants.js';
|
|
|
+import { FloatType } from '../constants.js';
|
|
|
import { Matrix4 } from '../math/Matrix4.js';
|
|
|
import { Mesh } from './Mesh.js';
|
|
|
import { RGBAFormat } from '../constants.js';
|
|
@@ -34,7 +34,7 @@ class MultiDrawRenderList {
|
|
|
|
|
|
}
|
|
|
|
|
|
- push( drawRange, z, index ) {
|
|
|
+ push( drawRange, z ) {
|
|
|
|
|
|
const pool = this.pool;
|
|
|
const list = this.list;
|
|
@@ -45,7 +45,6 @@ class MultiDrawRenderList {
|
|
|
start: - 1,
|
|
|
count: - 1,
|
|
|
z: - 1,
|
|
|
- index: - 1,
|
|
|
|
|
|
} );
|
|
|
|
|
@@ -58,7 +57,6 @@ class MultiDrawRenderList {
|
|
|
item.start = drawRange.start;
|
|
|
item.count = drawRange.count;
|
|
|
item.z = z;
|
|
|
- item.index = index;
|
|
|
|
|
|
}
|
|
|
|
|
@@ -71,6 +69,7 @@ class MultiDrawRenderList {
|
|
|
|
|
|
}
|
|
|
|
|
|
+const ID_ATTR_NAME = 'batchId';
|
|
|
const _matrix = /*@__PURE__*/ new Matrix4();
|
|
|
const _invMatrixWorld = /*@__PURE__*/ new Matrix4();
|
|
|
const _identityMatrix = /*@__PURE__*/ new Matrix4();
|
|
@@ -125,13 +124,13 @@ function copyAttributeData( src, target, targetOffset = 0 ) {
|
|
|
|
|
|
class BatchedMesh extends Mesh {
|
|
|
|
|
|
- get maxItemCount() {
|
|
|
+ get maxGeometryCount() {
|
|
|
|
|
|
- return this._maxItemCount;
|
|
|
+ return this._maxGeometryCount;
|
|
|
|
|
|
}
|
|
|
|
|
|
- constructor( maxDrawCount, maxVertexCount, maxIndexCount = maxVertexCount * 2, material ) {
|
|
|
+ constructor( maxGeometryCount, maxVertexCount, maxIndexCount = maxVertexCount * 2, material ) {
|
|
|
|
|
|
super( new BufferGeometry(), material );
|
|
|
|
|
@@ -142,33 +141,32 @@ class BatchedMesh extends Mesh {
|
|
|
this.boundingSphere = null;
|
|
|
this.customSort = null;
|
|
|
|
|
|
- // stores visible, active, and geometry id per object
|
|
|
- this._drawInfo = [];
|
|
|
-
|
|
|
- // geometry information
|
|
|
this._drawRanges = [];
|
|
|
this._reservedRanges = [];
|
|
|
+
|
|
|
+ this._visibility = [];
|
|
|
+ this._active = [];
|
|
|
this._bounds = [];
|
|
|
|
|
|
- this._maxItemCount = maxDrawCount;
|
|
|
+ this._maxGeometryCount = maxGeometryCount;
|
|
|
this._maxVertexCount = maxVertexCount;
|
|
|
this._maxIndexCount = maxIndexCount;
|
|
|
|
|
|
this._geometryInitialized = false;
|
|
|
this._geometryCount = 0;
|
|
|
- this._multiDrawCounts = new Int32Array( maxDrawCount );
|
|
|
- this._multiDrawStarts = new Int32Array( maxDrawCount );
|
|
|
+ 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
|
|
|
this._matricesTexture = null;
|
|
|
- this._indirectTexture = null;
|
|
|
- this._colorsTexture = null;
|
|
|
|
|
|
this._initMatricesTexture();
|
|
|
- this._initIndirectTexture();
|
|
|
+
|
|
|
+ // Local color per geometry by using data texture
|
|
|
+ this._colorsTexture = null;
|
|
|
|
|
|
}
|
|
|
|
|
@@ -181,7 +179,7 @@ class BatchedMesh extends Mesh {
|
|
|
// 32x32 pixel texture max 256 matrices * 4 pixels = (32 * 32)
|
|
|
// 64x64 pixel texture max 1024 matrices * 4 pixels = (64 * 64)
|
|
|
|
|
|
- let size = Math.sqrt( this._maxItemCount * 4 ); // 4 pixels needed for 1 matrix
|
|
|
+ let size = Math.sqrt( this._maxGeometryCount * 4 ); // 4 pixels needed for 1 matrix
|
|
|
size = Math.ceil( size / 4 ) * 4;
|
|
|
size = Math.max( size, 4 );
|
|
|
|
|
@@ -192,21 +190,9 @@ class BatchedMesh extends Mesh {
|
|
|
|
|
|
}
|
|
|
|
|
|
- _initIndirectTexture() {
|
|
|
-
|
|
|
- let size = Math.sqrt( this._maxItemCount );
|
|
|
- size = Math.ceil( size );
|
|
|
-
|
|
|
- const indirectArray = new Uint32Array( size * size );
|
|
|
- const indirectTexture = new DataTexture( indirectArray, size, size, RedIntegerFormat, UnsignedIntType );
|
|
|
-
|
|
|
- this._indirectTexture = indirectTexture;
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
_initColorsTexture() {
|
|
|
|
|
|
- let size = Math.sqrt( this._maxIndexCount );
|
|
|
+ let size = Math.sqrt( this._maxGeometryCount );
|
|
|
size = Math.ceil( size );
|
|
|
|
|
|
// 4 floats per RGBA pixel initialized to white
|
|
@@ -222,6 +208,7 @@ class BatchedMesh extends Mesh {
|
|
|
|
|
|
const geometry = this.geometry;
|
|
|
const maxVertexCount = this._maxVertexCount;
|
|
|
+ const maxGeometryCount = this._maxGeometryCount;
|
|
|
const maxIndexCount = this._maxIndexCount;
|
|
|
if ( this._geometryInitialized === false ) {
|
|
|
|
|
@@ -247,6 +234,11 @@ class BatchedMesh extends Mesh {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ const idArray = maxGeometryCount > 65536
|
|
|
+ ? new Uint32Array( maxVertexCount )
|
|
|
+ : new Uint16Array( maxVertexCount );
|
|
|
+ geometry.setAttribute( ID_ATTR_NAME, new BufferAttribute( idArray, 1 ) );
|
|
|
+
|
|
|
this._geometryInitialized = true;
|
|
|
|
|
|
}
|
|
@@ -256,6 +248,13 @@ class BatchedMesh extends Mesh {
|
|
|
// Make sure the geometry is compatible with the existing combined geometry attributes
|
|
|
_validateGeometry( geometry ) {
|
|
|
|
|
|
+ // check that the geometry doesn't have a version of our reserved id attribute
|
|
|
+ if ( geometry.getAttribute( ID_ATTR_NAME ) ) {
|
|
|
+
|
|
|
+ throw new Error( `BatchedMesh: Geometry cannot use attribute "${ ID_ATTR_NAME }"` );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
// check to ensure the geometries are using consistent attributes and indices
|
|
|
const batchGeometry = this.geometry;
|
|
|
if ( Boolean( geometry.getIndex() ) !== Boolean( batchGeometry.getIndex() ) ) {
|
|
@@ -266,6 +265,12 @@ class BatchedMesh extends Mesh {
|
|
|
|
|
|
for ( const attributeName in batchGeometry.attributes ) {
|
|
|
|
|
|
+ if ( attributeName === ID_ATTR_NAME ) {
|
|
|
+
|
|
|
+ continue;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
if ( ! geometry.hasAttribute( attributeName ) ) {
|
|
|
|
|
|
throw new Error( `BatchedMesh: Added geometry missing "${ attributeName }". All geometries must have consistent attributes.` );
|
|
@@ -301,12 +306,12 @@ class BatchedMesh extends Mesh {
|
|
|
|
|
|
const geometryCount = this._geometryCount;
|
|
|
const boundingBox = this.boundingBox;
|
|
|
- const drawInfo = this._drawInfo;
|
|
|
+ const active = this._active;
|
|
|
|
|
|
boundingBox.makeEmpty();
|
|
|
for ( let i = 0; i < geometryCount; i ++ ) {
|
|
|
|
|
|
- if ( drawInfo[ i ].active === false ) continue;
|
|
|
+ if ( active[ i ] === false ) continue;
|
|
|
|
|
|
this.getMatrixAt( i, _matrix );
|
|
|
this.getBoundingBoxAt( i, _box ).applyMatrix4( _matrix );
|
|
@@ -326,12 +331,12 @@ class BatchedMesh extends Mesh {
|
|
|
|
|
|
const geometryCount = this._geometryCount;
|
|
|
const boundingSphere = this.boundingSphere;
|
|
|
- const drawInfo = this._drawInfo;
|
|
|
+ const active = this._active;
|
|
|
|
|
|
boundingSphere.makeEmpty();
|
|
|
for ( let i = 0; i < geometryCount; i ++ ) {
|
|
|
|
|
|
- if ( drawInfo[ i ].active === false ) continue;
|
|
|
+ if ( active[ i ] === false ) continue;
|
|
|
|
|
|
this.getMatrixAt( i, _matrix );
|
|
|
this.getBoundingSphereAt( i, _sphere ).applyMatrix4( _matrix );
|
|
@@ -341,34 +346,6 @@ class BatchedMesh extends Mesh {
|
|
|
|
|
|
}
|
|
|
|
|
|
- addInstance( id ) {
|
|
|
-
|
|
|
- // ensure we're not over geometry
|
|
|
- if ( this._drawInfo.length >= this._maxItemCount ) {
|
|
|
-
|
|
|
- throw new Error( 'BatchedMesh: Maximum item count reached.' );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- this._drawInfo.push( {
|
|
|
-
|
|
|
- visible: true,
|
|
|
- active: true,
|
|
|
- geometryIndex: this._drawInfo[ id ].geometryIndex,
|
|
|
-
|
|
|
- } );
|
|
|
-
|
|
|
- // initialize the matrix
|
|
|
- const drawId = this._drawInfo.length - 1;
|
|
|
- const matricesTexture = this._matricesTexture;
|
|
|
- const matricesArray = matricesTexture.image.data;
|
|
|
- _identityMatrix.toArray( matricesArray, drawId * 16 );
|
|
|
- matricesTexture.needsUpdate = true;
|
|
|
-
|
|
|
- return drawId;
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
addGeometry( geometry, vertexCount = - 1, indexCount = - 1 ) {
|
|
|
|
|
|
this._initializeGeometry( geometry );
|
|
@@ -376,9 +353,9 @@ class BatchedMesh extends Mesh {
|
|
|
this._validateGeometry( geometry );
|
|
|
|
|
|
// ensure we're not over geometry
|
|
|
- if ( this._drawInfo.length >= this._maxItemCount ) {
|
|
|
+ if ( this._geometryCount >= this._maxGeometryCount ) {
|
|
|
|
|
|
- throw new Error( 'BatchedMesh: Maximum item count reached.' );
|
|
|
+ throw new Error( 'BatchedMesh: Maximum geometry count reached.' );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -456,10 +433,32 @@ class BatchedMesh extends Mesh {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ const visibility = this._visibility;
|
|
|
+ const active = this._active;
|
|
|
+ const matricesTexture = this._matricesTexture;
|
|
|
+ const matricesArray = this._matricesTexture.image.data;
|
|
|
+ const colorsTexture = this._colorsTexture;
|
|
|
+
|
|
|
+ // push new visibility states
|
|
|
+ visibility.push( true );
|
|
|
+ active.push( true );
|
|
|
+
|
|
|
// update id
|
|
|
const geometryId = this._geometryCount;
|
|
|
this._geometryCount ++;
|
|
|
|
|
|
+ // initialize matrix information
|
|
|
+ _identityMatrix.toArray( matricesArray, geometryId * 16 );
|
|
|
+ matricesTexture.needsUpdate = true;
|
|
|
+
|
|
|
+ // initialize the color to white
|
|
|
+ if ( colorsTexture !== null ) {
|
|
|
+
|
|
|
+ _whiteColor.toArray( colorsTexture.image.data, geometryId * 4 );
|
|
|
+ colorsTexture.needsUpdate = true;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
// add the reserved range and draw range objects
|
|
|
reservedRanges.push( reservedRange );
|
|
|
drawRanges.push( {
|
|
@@ -474,41 +473,26 @@ class BatchedMesh extends Mesh {
|
|
|
sphere: new Sphere()
|
|
|
} );
|
|
|
|
|
|
- // push new draw info states
|
|
|
- const drawInfo = this._drawInfo;
|
|
|
- const matricesTexture = this._matricesTexture;
|
|
|
- const matricesArray = this._matricesTexture.image.data;
|
|
|
- const colorsTexture = this._colorsTexture;
|
|
|
- const drawId = drawInfo.length;
|
|
|
- drawInfo.push( {
|
|
|
- visible: true,
|
|
|
- active: true,
|
|
|
- geometryIndex: geometryId,
|
|
|
- } );
|
|
|
-
|
|
|
- // initialize matrix information
|
|
|
- _identityMatrix.toArray( matricesArray, drawId * 16 );
|
|
|
- matricesTexture.needsUpdate = true;
|
|
|
+ // set the id for the geometry
|
|
|
+ const idAttribute = this.geometry.getAttribute( ID_ATTR_NAME );
|
|
|
+ for ( let i = 0; i < reservedRange.vertexCount; i ++ ) {
|
|
|
|
|
|
- // initialize the color to white
|
|
|
- if ( colorsTexture !== null ) {
|
|
|
-
|
|
|
- _whiteColor.toArray( colorsTexture.image.data, drawId * 4 );
|
|
|
- colorsTexture.needsUpdate = true;
|
|
|
+ idAttribute.setX( reservedRange.vertexStart + i, geometryId );
|
|
|
|
|
|
}
|
|
|
|
|
|
+ idAttribute.needsUpdate = true;
|
|
|
+
|
|
|
// update the geometry
|
|
|
- this.setGeometryAt( drawId, geometry );
|
|
|
+ this.setGeometryAt( geometryId, geometry );
|
|
|
|
|
|
- return drawId;
|
|
|
+ return geometryId;
|
|
|
|
|
|
}
|
|
|
|
|
|
setGeometryAt( id, geometry ) {
|
|
|
|
|
|
- const geometryId = this._drawInfo[ id ].geometryIndex;
|
|
|
- if ( geometryId >= this._geometryCount ) {
|
|
|
+ if ( id >= this._geometryCount ) {
|
|
|
|
|
|
throw new Error( 'BatchedMesh: Maximum geometry count reached.' );
|
|
|
|
|
@@ -520,7 +504,7 @@ class BatchedMesh extends Mesh {
|
|
|
const hasIndex = batchGeometry.getIndex() !== null;
|
|
|
const dstIndex = batchGeometry.getIndex();
|
|
|
const srcIndex = geometry.getIndex();
|
|
|
- const reservedRange = this._reservedRanges[ geometryId ];
|
|
|
+ const reservedRange = this._reservedRanges[ id ];
|
|
|
if (
|
|
|
hasIndex &&
|
|
|
srcIndex.count > reservedRange.indexCount ||
|
|
@@ -536,6 +520,12 @@ class BatchedMesh extends Mesh {
|
|
|
const vertexCount = reservedRange.vertexCount;
|
|
|
for ( const attributeName in batchGeometry.attributes ) {
|
|
|
|
|
|
+ if ( attributeName === ID_ATTR_NAME ) {
|
|
|
+
|
|
|
+ continue;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
// copy attribute data
|
|
|
const srcAttribute = geometry.getAttribute( attributeName );
|
|
|
const dstAttribute = batchGeometry.getAttribute( attributeName );
|
|
@@ -584,7 +574,7 @@ class BatchedMesh extends Mesh {
|
|
|
}
|
|
|
|
|
|
// store the bounding boxes
|
|
|
- const bound = this._bounds[ geometryId ];
|
|
|
+ const bound = this._bounds[ id ];
|
|
|
if ( geometry.boundingBox !== null ) {
|
|
|
|
|
|
bound.box.copy( geometry.boundingBox );
|
|
@@ -608,46 +598,67 @@ class BatchedMesh extends Mesh {
|
|
|
}
|
|
|
|
|
|
// set drawRange count
|
|
|
- const drawRange = this._drawRanges[ geometryId ];
|
|
|
+ const drawRange = this._drawRanges[ id ];
|
|
|
const posAttr = geometry.getAttribute( 'position' );
|
|
|
drawRange.count = hasIndex ? srcIndex.count : posAttr.count;
|
|
|
this._visibilityChanged = true;
|
|
|
|
|
|
- return geometryId;
|
|
|
+ return id;
|
|
|
|
|
|
}
|
|
|
|
|
|
- deleteInstance( id ) {
|
|
|
+ deleteGeometry( geometryId ) {
|
|
|
|
|
|
// Note: User needs to call optimize() afterward to pack the data.
|
|
|
|
|
|
- const drawInfo = this._drawInfo;
|
|
|
- if ( id >= drawInfo.length || drawInfo[ id ].active === false ) {
|
|
|
+ const active = this._active;
|
|
|
+ if ( geometryId >= active.length || active[ geometryId ] === false ) {
|
|
|
|
|
|
return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
- drawInfo[ id ].active = false;
|
|
|
+ active[ geometryId ] = false;
|
|
|
this._visibilityChanged = true;
|
|
|
|
|
|
return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
+ 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 ) {
|
|
|
|
|
|
- const drawInfo = this._drawInfo;
|
|
|
- if ( drawInfo[ id ].active === false ) {
|
|
|
+ const active = this._active;
|
|
|
+ if ( active[ id ] === false ) {
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
// compute bounding box
|
|
|
- const geometryId = drawInfo[ id ].geometryIndex;
|
|
|
- const bound = this._bounds[ geometryId ];
|
|
|
+ const bound = this._bounds[ id ];
|
|
|
const box = bound.box;
|
|
|
const geometry = this.geometry;
|
|
|
if ( bound.boxInitialized === false ) {
|
|
@@ -656,7 +667,7 @@ class BatchedMesh extends Mesh {
|
|
|
|
|
|
const index = geometry.index;
|
|
|
const position = geometry.attributes.position;
|
|
|
- const drawRange = this._drawRanges[ geometryId ];
|
|
|
+ const drawRange = this._drawRanges[ id ];
|
|
|
for ( let i = drawRange.start, l = drawRange.start + drawRange.count; i < l; i ++ ) {
|
|
|
|
|
|
let iv = i;
|
|
@@ -682,28 +693,27 @@ class BatchedMesh extends Mesh {
|
|
|
// get bounding sphere and compute it if it doesn't exist
|
|
|
getBoundingSphereAt( id, target ) {
|
|
|
|
|
|
- const drawInfo = this._drawInfo;
|
|
|
- if ( drawInfo[ id ].active === false ) {
|
|
|
+ const active = this._active;
|
|
|
+ if ( active[ id ] === false ) {
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
// compute bounding sphere
|
|
|
- const geometryId = drawInfo[ id ].geometryIndex;
|
|
|
- const bound = this._bounds[ geometryId ];
|
|
|
+ const bound = this._bounds[ id ];
|
|
|
const sphere = bound.sphere;
|
|
|
const geometry = this.geometry;
|
|
|
if ( bound.sphereInitialized === false ) {
|
|
|
|
|
|
sphere.makeEmpty();
|
|
|
|
|
|
- this.getBoundingBoxAt( geometryId, _box );
|
|
|
+ this.getBoundingBoxAt( id, _box );
|
|
|
_box.getCenter( sphere.center );
|
|
|
|
|
|
const index = geometry.index;
|
|
|
const position = geometry.attributes.position;
|
|
|
- const drawRange = this._drawRanges[ geometryId ];
|
|
|
+ const drawRange = this._drawRanges[ id ];
|
|
|
|
|
|
let maxRadiusSq = 0;
|
|
|
for ( let i = drawRange.start, l = drawRange.start + drawRange.count; i < l; i ++ ) {
|
|
@@ -730,42 +740,44 @@ class BatchedMesh extends Mesh {
|
|
|
|
|
|
}
|
|
|
|
|
|
- setMatrixAt( id, matrix ) {
|
|
|
+ setMatrixAt( geometryId, matrix ) {
|
|
|
|
|
|
// @TODO: Map geometryId to index of the arrays because
|
|
|
// optimize() can make geometryId mismatch the index
|
|
|
|
|
|
- const drawInfo = this._drawInfo;
|
|
|
+ const active = this._active;
|
|
|
const matricesTexture = this._matricesTexture;
|
|
|
const matricesArray = this._matricesTexture.image.data;
|
|
|
- if ( id >= drawInfo.length || drawInfo[ id ].active === false ) {
|
|
|
+ const geometryCount = this._geometryCount;
|
|
|
+ if ( geometryId >= geometryCount || active[ geometryId ] === false ) {
|
|
|
|
|
|
return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
- matrix.toArray( matricesArray, id * 16 );
|
|
|
+ matrix.toArray( matricesArray, geometryId * 16 );
|
|
|
matricesTexture.needsUpdate = true;
|
|
|
|
|
|
return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
- getMatrixAt( id, matrix ) {
|
|
|
+ getMatrixAt( geometryId, matrix ) {
|
|
|
|
|
|
- const drawInfo = this._drawInfo;
|
|
|
+ const active = this._active;
|
|
|
const matricesArray = this._matricesTexture.image.data;
|
|
|
- if ( id >= drawInfo.length || drawInfo[ id ].active === false ) {
|
|
|
+ const geometryCount = this._geometryCount;
|
|
|
+ if ( geometryId >= geometryCount || active[ geometryId ] === false ) {
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
- return matrix.fromArray( matricesArray, id * 16 );
|
|
|
+ return matrix.fromArray( matricesArray, geometryId * 16 );
|
|
|
|
|
|
}
|
|
|
|
|
|
- setColorAt( id, color ) {
|
|
|
+ setColorAt( geometryId, color ) {
|
|
|
|
|
|
if ( this._colorsTexture === null ) {
|
|
|
|
|
@@ -773,79 +785,89 @@ class BatchedMesh extends Mesh {
|
|
|
|
|
|
}
|
|
|
|
|
|
- // @TODO: Map id to index of the arrays because
|
|
|
- // optimize() can make id mismatch the index
|
|
|
+ // @TODO: Map geometryId to index of the arrays because
|
|
|
+ // optimize() can make geometryId mismatch the index
|
|
|
|
|
|
+ const active = this._active;
|
|
|
const colorsTexture = this._colorsTexture;
|
|
|
const colorsArray = this._colorsTexture.image.data;
|
|
|
- const drawInfo = this._drawInfo;
|
|
|
- if ( id >= drawInfo.length || drawInfo[ id ].active === false ) {
|
|
|
+ const geometryCount = this._geometryCount;
|
|
|
+ if ( geometryId >= geometryCount || active[ geometryId ] === false ) {
|
|
|
|
|
|
return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
- color.toArray( colorsArray, id * 4 );
|
|
|
+ color.toArray( colorsArray, geometryId * 4 );
|
|
|
colorsTexture.needsUpdate = true;
|
|
|
|
|
|
return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
- getColorAt( id, color ) {
|
|
|
+ getColorAt( geometryId, color ) {
|
|
|
|
|
|
+ const active = this._active;
|
|
|
const colorsArray = this._colorsTexture.image.data;
|
|
|
- const drawInfo = this._drawInfo;
|
|
|
- if ( id >= drawInfo.length || drawInfo[ id ].active === false ) {
|
|
|
+ const geometryCount = this._geometryCount;
|
|
|
+ if ( geometryId >= geometryCount || active[ geometryId ] === false ) {
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
- return color.fromArray( colorsArray, id * 4 );
|
|
|
+ return color.fromArray( colorsArray, geometryId * 4 );
|
|
|
|
|
|
}
|
|
|
|
|
|
- setVisibleAt( id, value ) {
|
|
|
+ setVisibleAt( geometryId, value ) {
|
|
|
+
|
|
|
+ const visibility = this._visibility;
|
|
|
+ const active = this._active;
|
|
|
+ const geometryCount = this._geometryCount;
|
|
|
|
|
|
// if the geometry is out of range, not active, or visibility state
|
|
|
// does not change then return early
|
|
|
- const drawInfo = this._drawInfo;
|
|
|
if (
|
|
|
- id >= drawInfo.length ||
|
|
|
- drawInfo[ id ].active === false ||
|
|
|
- drawInfo[ id ].visible === value
|
|
|
+ geometryId >= geometryCount ||
|
|
|
+ active[ geometryId ] === false ||
|
|
|
+ visibility[ geometryId ] === value
|
|
|
) {
|
|
|
|
|
|
return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
- drawInfo[ id ].visible = value;
|
|
|
+ visibility[ geometryId ] = value;
|
|
|
this._visibilityChanged = true;
|
|
|
|
|
|
return this;
|
|
|
|
|
|
}
|
|
|
|
|
|
- getVisibleAt( id ) {
|
|
|
+ getVisibleAt( geometryId ) {
|
|
|
+
|
|
|
+ const visibility = this._visibility;
|
|
|
+ const active = this._active;
|
|
|
+ const geometryCount = this._geometryCount;
|
|
|
|
|
|
// return early if the geometry is out of range or not active
|
|
|
- const drawInfo = this._drawInfo;
|
|
|
- if ( id >= drawInfo.length || drawInfo[ id ].active === false ) {
|
|
|
+ if ( geometryId >= geometryCount || active[ geometryId ] === false ) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
- return drawInfo[ id ].visible;
|
|
|
+ return visibility[ geometryId ];
|
|
|
|
|
|
}
|
|
|
|
|
|
raycast( raycaster, intersects ) {
|
|
|
|
|
|
- const drawInfo = this._drawInfo;
|
|
|
+ const visibility = this._visibility;
|
|
|
+ const active = this._active;
|
|
|
const drawRanges = this._drawRanges;
|
|
|
+ const geometryCount = this._geometryCount;
|
|
|
const matrixWorld = this.matrixWorld;
|
|
|
const batchGeometry = this.geometry;
|
|
|
|
|
@@ -865,16 +887,15 @@ class BatchedMesh extends Mesh {
|
|
|
|
|
|
}
|
|
|
|
|
|
- for ( let i = 0, l = drawInfo.length; i < l; i ++ ) {
|
|
|
+ for ( let i = 0; i < geometryCount; i ++ ) {
|
|
|
|
|
|
- if ( ! drawInfo[ i ].visible || ! drawInfo[ i ].active ) {
|
|
|
+ if ( ! visibility[ i ] || ! active[ i ] ) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
- const geometryId = drawInfo[ i ].geometryIndex;
|
|
|
- const drawRange = drawRanges[ geometryId ];
|
|
|
+ const drawRange = drawRanges[ i ];
|
|
|
_mesh.geometry.setDrawRange( drawRange.start, drawRange.count );
|
|
|
|
|
|
// ge the intersects
|
|
@@ -917,7 +938,8 @@ class BatchedMesh extends Mesh {
|
|
|
this._drawRanges = source._drawRanges.map( range => ( { ...range } ) );
|
|
|
this._reservedRanges = source._reservedRanges.map( range => ( { ...range } ) );
|
|
|
|
|
|
- this._drawInfo = source._info.map( inf => ( { ...inf } ) );
|
|
|
+ this._visibility = source._visibility.slice();
|
|
|
+ this._active = source._active.slice();
|
|
|
this._bounds = source._bounds.map( bound => ( {
|
|
|
boxInitialized: bound.boxInitialized,
|
|
|
box: bound.box.clone(),
|
|
@@ -926,7 +948,7 @@ class BatchedMesh extends Mesh {
|
|
|
sphere: bound.sphere.clone()
|
|
|
} ) );
|
|
|
|
|
|
- this._maxItemCount = source._maxItemCount;
|
|
|
+ this._maxGeometryCount = source._maxGeometryCount;
|
|
|
this._maxVertexCount = source._maxVertexCount;
|
|
|
this._maxIndexCount = source._maxIndexCount;
|
|
|
|
|
@@ -957,9 +979,6 @@ class BatchedMesh extends Mesh {
|
|
|
this._matricesTexture.dispose();
|
|
|
this._matricesTexture = null;
|
|
|
|
|
|
- this._indirectTexture.dispose();
|
|
|
- this._indirectTexture = null;
|
|
|
-
|
|
|
if ( this._colorsTexture !== null ) {
|
|
|
|
|
|
this._colorsTexture.dispose();
|
|
@@ -986,13 +1005,12 @@ class BatchedMesh extends Mesh {
|
|
|
const index = geometry.getIndex();
|
|
|
const bytesPerElement = index === null ? 1 : index.array.BYTES_PER_ELEMENT;
|
|
|
|
|
|
- const drawInfo = this._drawInfo;
|
|
|
+ const active = this._active;
|
|
|
+ const visibility = this._visibility;
|
|
|
const multiDrawStarts = this._multiDrawStarts;
|
|
|
const multiDrawCounts = this._multiDrawCounts;
|
|
|
const drawRanges = this._drawRanges;
|
|
|
const perObjectFrustumCulled = this.perObjectFrustumCulled;
|
|
|
- const indirectTexture = this._indirectTexture;
|
|
|
- const indirectArray = indirectTexture.image.data;
|
|
|
|
|
|
// prepare the frustum in the local frame
|
|
|
if ( perObjectFrustumCulled ) {
|
|
@@ -1015,9 +1033,9 @@ class BatchedMesh extends Mesh {
|
|
|
_vector.setFromMatrixPosition( camera.matrixWorld ).applyMatrix4( _invMatrixWorld );
|
|
|
_forward.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ).transformDirection( _invMatrixWorld );
|
|
|
|
|
|
- for ( let i = 0, l = drawInfo.length; i < l; i ++ ) {
|
|
|
+ for ( let i = 0, l = visibility.length; i < l; i ++ ) {
|
|
|
|
|
|
- if ( drawInfo[ i ].visible && drawInfo[ i ].active ) {
|
|
|
+ if ( visibility[ i ] && active[ i ] ) {
|
|
|
|
|
|
// get the bounds in world space
|
|
|
this.getMatrixAt( i, _matrix );
|
|
@@ -1035,7 +1053,7 @@ class BatchedMesh extends Mesh {
|
|
|
|
|
|
// get the distance from camera used for sorting
|
|
|
const z = _temp.subVectors( _sphere.center, _vector ).dot( _forward );
|
|
|
- _renderList.push( drawRanges[ drawInfo[ i ].geometryIndex ], z, i );
|
|
|
+ _renderList.push( drawRanges[ i ], z );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -1061,7 +1079,6 @@ class BatchedMesh extends Mesh {
|
|
|
const item = list[ i ];
|
|
|
multiDrawStarts[ count ] = item.start * bytesPerElement;
|
|
|
multiDrawCounts[ count ] = item.count;
|
|
|
- indirectArray[ count ] = item.index;
|
|
|
count ++;
|
|
|
|
|
|
}
|
|
@@ -1070,9 +1087,9 @@ class BatchedMesh extends Mesh {
|
|
|
|
|
|
} else {
|
|
|
|
|
|
- for ( let i = 0, l = drawInfo.length; i < l; i ++ ) {
|
|
|
+ for ( let i = 0, l = visibility.length; i < l; i ++ ) {
|
|
|
|
|
|
- if ( drawInfo[ i ].visible && drawInfo[ i ].active ) {
|
|
|
+ if ( visibility[ i ] && active[ i ] ) {
|
|
|
|
|
|
// determine whether the batched geometry is within the frustum
|
|
|
let culled = false;
|
|
@@ -1087,10 +1104,9 @@ class BatchedMesh extends Mesh {
|
|
|
|
|
|
if ( ! culled ) {
|
|
|
|
|
|
- const range = drawRanges[ drawInfo[ i ].geometryIndex ];
|
|
|
+ const range = drawRanges[ i ];
|
|
|
multiDrawStarts[ count ] = range.start * bytesPerElement;
|
|
|
multiDrawCounts[ count ] = range.count;
|
|
|
- indirectArray[ count ] = i;
|
|
|
count ++;
|
|
|
|
|
|
}
|
|
@@ -1101,7 +1117,6 @@ class BatchedMesh extends Mesh {
|
|
|
|
|
|
}
|
|
|
|
|
|
- indirectTexture.needsUpdate = true;
|
|
|
this._multiDrawCount = count;
|
|
|
this._visibilityChanged = false;
|
|
|
|