Ver código fonte

Revert "BatchedMesh: Add support for Instanced rendering with sorting, frustu…" (#28461)

This reverts commit 02ed248659a4787aaae25cd18e246e02baa9b47c.
Garrett Johnson 1 ano atrás
pai
commit
496acf988a

+ 3 - 13
examples/webgl_mesh_batch.html

@@ -179,8 +179,8 @@
 		function initBatchedMesh() {
 
 			const geometryCount = api.count;
-			const vertexCount = geometries.length * 512;
-			const indexCount = geometries.length * 1024;
+			const vertexCount = api.count * 512;
+			const indexCount = api.count * 1024;
 
 			const euler = new THREE.Euler();
 			const matrix = new THREE.Matrix4();
@@ -194,17 +194,7 @@
 
 			for ( let i = 0; i < api.count; i ++ ) {
 
-				let id;
-				if ( i < geometries.length ) {
-
-					id = mesh.addGeometry( geometries[ i % geometries.length ] );
-
-				} else {
-
-					id = mesh.addInstance( i % geometries.length );
-
-				}
-
+				const id = mesh.addGeometry( geometries[ i % geometries.length ] );
 				mesh.setMatrixAt( id, randomizeMatrix( matrix ) );
 
 				const rotationMatrix = new THREE.Matrix4();

+ 173 - 158
src/objects/BatchedMesh.js

@@ -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;
 

+ 1 - 22
src/renderers/WebGLRenderer.js

@@ -861,25 +861,7 @@ class WebGLRenderer {
 
 				} else {
 
-					if ( ! extensions.get( 'WEBGL_multi_draw' ) ) {
-
-						const starts = object._multiDrawStarts;
-						const counts = object._multiDrawCounts;
-						const drawCount = object._multiDrawCount;
-						const bytesPerElement = index ? attributes.get( index ).bytesPerElement : 1;
-						const uniforms = properties.get( material ).currentProgram.getUniforms();
-						for ( let i = 0; i < drawCount; i ++ ) {
-
-							uniforms.setValue( _gl, '_gl_DrawID', i );
-							renderer.render( starts[ i ] / bytesPerElement, counts[ i ] );
-
-						}
-
-					} else {
-
-						renderer.renderMultiDraw( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount );
-
-					}
+					renderer.renderMultiDraw( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount );
 
 				}
 
@@ -2035,9 +2017,6 @@ class WebGLRenderer {
 				p_uniforms.setOptional( _gl, object, 'batchingTexture' );
 				p_uniforms.setValue( _gl, 'batchingTexture', object._matricesTexture, textures );
 
-				p_uniforms.setOptional( _gl, object, 'batchingIdTexture' );
-				p_uniforms.setValue( _gl, 'batchingIdTexture', object._indirectTexture, textures );
-
 				p_uniforms.setOptional( _gl, object, 'batchingColorTexture' );
 				if ( object._colorsTexture !== null ) {
 

+ 1 - 16
src/renderers/shaders/ShaderChunk/batching_pars_vertex.glsl.js

@@ -1,12 +1,7 @@
 export default /* glsl */`
 #ifdef USE_BATCHING
-	#if ! defined( GL_ANGLE_multi_draw )
-	#define gl_DrawID _gl_DrawID
-	uniform int _gl_DrawID;
-	#endif
-
+	attribute float batchId;
 	uniform highp sampler2D batchingTexture;
-	uniform highp usampler2D batchingIdTexture;
 	mat4 getBatchingMatrix( const in float i ) {
 
 		int size = textureSize( batchingTexture, 0 ).x;
@@ -20,16 +15,6 @@ export default /* glsl */`
 		return mat4( v1, v2, v3, v4 );
 
 	}
-
-	float getIndirectIndex( const in int i ) {
-
-		int size = textureSize( batchingIdTexture, 0 ).x;
-		int x = i % size;
-		int y = i / size;
-		return float( texelFetch( batchingIdTexture, ivec2( x, y ), 0 ).r );
-
-	}
-
 #endif
 
 #ifdef USE_BATCHING_COLOR

+ 1 - 1
src/renderers/shaders/ShaderChunk/batching_vertex.glsl.js

@@ -1,5 +1,5 @@
 export default /* glsl */`
 #ifdef USE_BATCHING
-	mat4 batchingMatrix = getBatchingMatrix( getIndirectIndex( gl_DrawID ) );
+	mat4 batchingMatrix = getBatchingMatrix( batchId );
 #endif
 `;

+ 1 - 1
src/renderers/shaders/ShaderChunk/color_vertex.glsl.js

@@ -23,7 +23,7 @@ export default /* glsl */`
 
 #ifdef USE_BATCHING_COLOR
 
-	vec3 batchingColor = getBatchingColor( getIndirectIndex( gl_DrawID ) );
+	vec3 batchingColor = getBatchingColor( batchId );
 
 	vColor.xyz *= batchingColor.xyz;
 

+ 19 - 6
src/renderers/webgl/WebGLBufferRenderer.js

@@ -31,16 +31,29 @@ function WebGLBufferRenderer( gl, extensions, info ) {
 		if ( drawCount === 0 ) return;
 
 		const extension = extensions.get( 'WEBGL_multi_draw' );
-		extension.multiDrawArraysWEBGL( mode, starts, 0, counts, 0, drawCount );
 
-		let elementCount = 0;
-		for ( let i = 0; i < drawCount; i ++ ) {
+		if ( extension === null ) {
 
-			elementCount += counts[ i ];
+			for ( let i = 0; i < drawCount; i ++ ) {
 
-		}
+				this.render( starts[ i ], counts[ i ] );
+
+			}
 
-		info.update( elementCount, mode, 1 );
+		} else {
+
+			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 );
+
+		}
 
 	}
 

+ 18 - 6
src/renderers/webgl/WebGLIndexedBufferRenderer.js

@@ -40,17 +40,29 @@ function WebGLIndexedBufferRenderer( gl, extensions, info ) {
 		if ( drawCount === 0 ) return;
 
 		const extension = extensions.get( 'WEBGL_multi_draw' );
-		extension.multiDrawElementsWEBGL( mode, counts, 0, type, starts, 0, drawCount );
 
-		let elementCount = 0;
-		for ( let i = 0; i < drawCount; i ++ ) {
+		if ( extension === null ) {
+
+			for ( let i = 0; i < drawCount; i ++ ) {
 
-			elementCount += counts[ i ];
+				this.render( starts[ i ] / bytesPerElement, counts[ i ] );
 
-		}
+			}
+
+		} else {
+
+			extension.multiDrawElementsWEBGL( mode, counts, 0, type, starts, 0, drawCount );
 
-		info.update( elementCount, mode, 1 );
+			let elementCount = 0;
+			for ( let i = 0; i < drawCount; i ++ ) {
+
+				elementCount += counts[ i ];
 
+			}
+
+			info.update( elementCount, mode, 1 );
+
+		}
 
 	}
 

+ 1 - 1
src/renderers/webgl/WebGLPrograms.js

@@ -352,7 +352,7 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 			index0AttributeName: material.index0AttributeName,
 
 			extensionClipCullDistance: HAS_EXTENSIONS && material.extensions.clipCullDistance === true && extensions.has( 'WEBGL_clip_cull_distance' ),
-			extensionMultiDraw: ( HAS_EXTENSIONS && material.extensions.multiDraw === true || IS_BATCHEDMESH ) && extensions.has( 'WEBGL_multi_draw' ),
+			extensionMultiDraw: HAS_EXTENSIONS && material.extensions.multiDraw === true && extensions.has( 'WEBGL_multi_draw' ),
 
 			rendererExtensionParallelShaderCompile: extensions.has( 'KHR_parallel_shader_compile' ),