Browse Source

Allow InstancedMesh provide a unique ID for WebGLBindingStates (#32556)

Ondřej Španěl 2 months ago
parent
commit
decc02ea4d

+ 1 - 1
src/renderers/WebGLRenderer.js

@@ -446,7 +446,7 @@ class WebGLRenderer {
 			attributes = new WebGLAttributes( _gl );
 			bindingStates = new WebGLBindingStates( _gl, attributes );
 			geometries = new WebGLGeometries( _gl, attributes, info, bindingStates );
-			objects = new WebGLObjects( _gl, geometries, attributes, info );
+			objects = new WebGLObjects( _gl, geometries, attributes, bindingStates, info );
 			morphtargets = new WebGLMorphtargets( _gl, capabilities, textures );
 			clipping = new WebGLClipping( properties );
 			programCache = new WebGLPrograms( _this, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping );

+ 99 - 27
src/renderers/webgl/WebGLBindingStates.js

@@ -14,7 +14,7 @@ function WebGLBindingStates( gl, attributes ) {
 
 		let updateBuffers = false;
 
-		const state = getBindingState( geometry, program, material );
+		const state = getBindingState( object, geometry, program, material );
 
 		if ( currentState !== state ) {
 
@@ -67,16 +67,28 @@ function WebGLBindingStates( gl, attributes ) {
 
 	}
 
-	function getBindingState( geometry, program, material ) {
+	function getBindingState( object, geometry, program, material ) {
 
 		const wireframe = ( material.wireframe === true );
 
-		let programMap = bindingStates[ geometry.id ];
+		let objectMap = bindingStates[ geometry.id ];
+
+		if ( objectMap === undefined ) {
+
+			objectMap = {};
+			bindingStates[ geometry.id ] = objectMap;
+
+		}
+
+		// Each InstancedMesh requires unique binding states because it contains instanced attributes.
+		const objectId = ( object.isInstancedMesh === true ) ? object.id : 0;
+
+		let programMap = objectMap[ objectId ];
 
 		if ( programMap === undefined ) {
 
 			programMap = {};
-			bindingStates[ geometry.id ] = programMap;
+			objectMap[ objectId ] = programMap;
 
 		}
 
@@ -477,21 +489,27 @@ function WebGLBindingStates( gl, attributes ) {
 
 		for ( const geometryId in bindingStates ) {
 
-			const programMap = bindingStates[ geometryId ];
+			const objectMap = bindingStates[ geometryId ];
 
-			for ( const programId in programMap ) {
+			for ( const objectId in objectMap ) {
 
-				const stateMap = programMap[ programId ];
+				const programMap = objectMap[ objectId ];
 
-				for ( const wireframe in stateMap ) {
+				for ( const programId in programMap ) {
 
-					deleteVertexArrayObject( stateMap[ wireframe ].object );
+					const stateMap = programMap[ programId ];
 
-					delete stateMap[ wireframe ];
+					for ( const wireframe in stateMap ) {
 
-				}
+						deleteVertexArrayObject( stateMap[ wireframe ].object );
 
-				delete programMap[ programId ];
+						delete stateMap[ wireframe ];
+
+					}
+
+					delete programMap[ programId ];
+
+				}
 
 			}
 
@@ -505,21 +523,27 @@ function WebGLBindingStates( gl, attributes ) {
 
 		if ( bindingStates[ geometry.id ] === undefined ) return;
 
-		const programMap = bindingStates[ geometry.id ];
+		const objectMap = bindingStates[ geometry.id ];
 
-		for ( const programId in programMap ) {
+		for ( const objectId in objectMap ) {
 
-			const stateMap = programMap[ programId ];
+			const programMap = objectMap[ objectId ];
 
-			for ( const wireframe in stateMap ) {
+			for ( const programId in programMap ) {
 
-				deleteVertexArrayObject( stateMap[ wireframe ].object );
+				const stateMap = programMap[ programId ];
 
-				delete stateMap[ wireframe ];
+				for ( const wireframe in stateMap ) {
 
-			}
+					deleteVertexArrayObject( stateMap[ wireframe ].object );
 
-			delete programMap[ programId ];
+					delete stateMap[ wireframe ];
+
+				}
+
+				delete programMap[ programId ];
+
+			}
 
 		}
 
@@ -531,26 +555,73 @@ function WebGLBindingStates( gl, attributes ) {
 
 		for ( const geometryId in bindingStates ) {
 
-			const programMap = bindingStates[ geometryId ];
+			const objectMap = bindingStates[ geometryId ];
+
+			for ( const objectId in objectMap ) {
+
+				const programMap = objectMap[ objectId ];
+
+				if ( programMap[ program.id ] === undefined ) continue;
+
+				const stateMap = programMap[ program.id ];
+
+				for ( const wireframe in stateMap ) {
+
+					deleteVertexArrayObject( stateMap[ wireframe ].object );
+
+					delete stateMap[ wireframe ];
+
+				}
+
+				delete programMap[ program.id ];
+
+			}
+
+		}
+
+	}
+
+	function releaseStatesOfObject( object ) {
+
+		for ( const geometryId in bindingStates ) {
+
+			const objectMap = bindingStates[ geometryId ];
 
-			if ( programMap[ program.id ] === undefined ) continue;
+			const objectId = ( object.isInstancedMesh === true ) ? object.id : 0;
 
-			const stateMap = programMap[ program.id ];
+			const programMap = objectMap[ objectId ];
 
-			for ( const wireframe in stateMap ) {
+			if ( programMap === undefined ) continue;
 
-				deleteVertexArrayObject( stateMap[ wireframe ].object );
+			for ( const programId in programMap ) {
 
-				delete stateMap[ wireframe ];
+				const stateMap = programMap[ programId ];
+
+				for ( const wireframe in stateMap ) {
+
+					deleteVertexArrayObject( stateMap[ wireframe ].object );
+
+					delete stateMap[ wireframe ];
+
+				}
+
+				delete programMap[ programId ];
 
 			}
 
-			delete programMap[ program.id ];
+			delete objectMap[ objectId ];
+
+			if ( Object.keys( objectMap ).length === 0 ) {
+
+				delete bindingStates[ geometryId ];
+
+			}
 
 		}
 
 	}
 
+
 	function reset() {
 
 		resetDefaultState();
@@ -580,6 +651,7 @@ function WebGLBindingStates( gl, attributes ) {
 		resetDefaultState: resetDefaultState,
 		dispose: dispose,
 		releaseStatesOfGeometry: releaseStatesOfGeometry,
+		releaseStatesOfObject: releaseStatesOfObject,
 		releaseStatesOfProgram: releaseStatesOfProgram,
 
 		initAttributes: initAttributes,

+ 3 - 1
src/renderers/webgl/WebGLObjects.js

@@ -1,4 +1,4 @@
-function WebGLObjects( gl, geometries, attributes, info ) {
+function WebGLObjects( gl, geometries, attributes, bindingStates, info ) {
 
 	let updateMap = new WeakMap();
 
@@ -73,6 +73,8 @@ function WebGLObjects( gl, geometries, attributes, info ) {
 
 		instancedMesh.removeEventListener( 'dispose', onInstancedMeshDispose );
 
+		bindingStates.releaseStatesOfObject( instancedMesh );
+
 		attributes.remove( instancedMesh.instanceMatrix );
 
 		if ( instancedMesh.instanceColor !== null ) attributes.remove( instancedMesh.instanceColor );

粤ICP备19079148号