Browse Source

Merge pull request #15431 from nextbitlabs/feature/#15321-improve-gtlf-loader-cache

#15321: use object as cache for GTLF loader instead of array
Mr.doob 6 years ago
parent
commit
b4ac5c5ef3
1 changed files with 47 additions and 55 deletions
  1. 47 55
      examples/js/loaders/GLTFLoader.js

+ 47 - 55
examples/js/loaders/GLTFLoader.js

@@ -1362,8 +1362,10 @@ THREE.GLTFLoader = ( function () {
 				var accessor = target.POSITION !== undefined
 					? parser.getDependency( 'accessor', target.POSITION )
 						.then( function ( accessor ) {
+
 							// Cloning not to pollute original accessor below
 							return cloneBufferAttribute( accessor );
+
 						} )
 					: geometry.attributes.position;
 
@@ -1377,7 +1379,9 @@ THREE.GLTFLoader = ( function () {
 				var accessor = target.NORMAL !== undefined
 					? parser.getDependency( 'accessor', target.NORMAL )
 						.then( function ( accessor ) {
+
 							return cloneBufferAttribute( accessor );
+
 						} )
 					: geometry.attributes.normal;
 
@@ -1515,30 +1519,6 @@ THREE.GLTFLoader = ( function () {
 		}
 
 	}
-
-	function isPrimitiveEqual( a, b ) {
-
-		var dracoExtA = a.extensions ? a.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ] : undefined;
-		var dracoExtB = b.extensions ? b.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ] : undefined;
-
-		if ( dracoExtA && dracoExtB ) {
-
-			if ( dracoExtA.bufferView !== dracoExtB.bufferView ) return false;
-
-			return isObjectEqual( dracoExtA.attributes, dracoExtB.attributes );
-
-		}
-
-		if ( a.indices !== b.indices ) {
-
-			return false;
-
-		}
-
-		return isObjectEqual( a.attributes, b.attributes );
-
-	}
-
 	function isObjectEqual( a, b ) {
 
 		if ( Object.keys( a ).length !== Object.keys( b ).length ) return false;
@@ -1553,59 +1533,68 @@ THREE.GLTFLoader = ( function () {
 
 	}
 
-	function isArrayEqual( a, b ) {
+	function createPrimitiveKey( primitiveDef ) {
 
-		if ( a.length !== b.length ) return false;
+		var dracoExtension = primitiveDef.extensions && primitiveDef.extensions[ EXTENSIONS.KHR_DRACO_MESH_COMPRESSION ];
+		var geometryKey;
 
-		for ( var i = 0, il = a.length; i < il; i ++ ) {
+		if ( dracoExtension ) {
+
+			geometryKey = 'draco:' + dracoExtension.bufferView
+				+ ':' + dracoExtension.indices
+				+ ':' + createAttributesKey( dracoExtension.attributes );
 
-			if ( a[ i ] !== b[ i ] ) return false;
+		} else {
+
+			geometryKey = primitiveDef.indices + ':' + createAttributesKey( primitiveDef.attributes ) + ':' + primitiveDef.mode;
 
 		}
 
-		return true;
+		return geometryKey;
 
 	}
 
-	function getCachedGeometry( cache, newPrimitive ) {
+	function createAttributesKey( attributes ) {
+
+		var attributesKey = '';
 
-		for ( var i = 0, il = cache.length; i < il; i ++ ) {
+		var keys = Object.keys( attributes ).sort();
 
-			var cached = cache[ i ];
+		for ( var i = 0, il = keys.length; i < il; i ++ ) {
 
-			if ( isPrimitiveEqual( cached.primitive, newPrimitive ) ) return cached.promise;
+			attributesKey += keys[ i ] + ':' + attributes[ keys[ i ] ] + ';';
 
 		}
 
-		return null;
+		return attributesKey;
 
 	}
 
-	function getCachedCombinedGeometry( cache, geometries ) {
+	function createArrayKeyBufferGeometry( a ) {
 
-		for ( var i = 0, il = cache.length; i < il; i ++ ) {
+		var arrayKey = '';
 
-			var cached = cache[ i ];
+		for ( var i = 0, il = a.length; i < il; i ++ ) {
 
-			if ( isArrayEqual( geometries, cached.baseGeometries ) ) return cached.geometry;
+			arrayKey += ':' + a[ i ].uuid;
 
 		}
 
-		return null;
+		return arrayKey;
 
 	}
 
-	function getCachedMultiPassGeometry( cache, geometry, primitives ) {
+	function createMultiPassGeometryKey( geometry, primitives ) {
 
-		for ( var i = 0, il = cache.length; i < il; i ++ ) {
+		var key = geometry.uuid;
 
-			var cached = cache[ i ];
+		for ( var i = 0, il = primitives.length; i < il; i ++ ) {
 
-			if ( geometry === cached.baseGeometry && isArrayEqual( primitives, cached.primitives ) ) return cached.geometry;
+			key += i + createPrimitiveKey( primitives[ i ] );
 
 		}
 
-		return null;
+		return key;
 
 	}
 
@@ -1688,9 +1677,9 @@ THREE.GLTFLoader = ( function () {
 		this.cache = new GLTFRegistry();
 
 		// BufferGeometry caching
-		this.primitiveCache = [];
-		this.multiplePrimitivesCache = [];
-		this.multiPassGeometryCache = [];
+		this.primitiveCache = {};
+		this.multiplePrimitivesCache = {};
+		this.multiPassGeometryCache = {};
 
 		this.textureLoader = new THREE.TextureLoader( this.options.manager );
 		this.textureLoader.setCrossOrigin( this.options.crossOrigin );
@@ -2534,14 +2523,15 @@ THREE.GLTFLoader = ( function () {
 		for ( var i = 0, il = primitives.length; i < il; i ++ ) {
 
 			var primitive = primitives[ i ];
+			var cacheKey = createPrimitiveKey( primitive );
 
 			// See if we've already created this geometry
-			var cached = getCachedGeometry( cache, primitive );
+			var cached = cache[ cacheKey ];
 
 			if ( cached ) {
 
 				// Use the cached geometry if it exists
-				pending.push( cached );
+				pending.push( cached.promise );
 
 			} else {
 
@@ -2560,7 +2550,7 @@ THREE.GLTFLoader = ( function () {
 				}
 
 				// Cache this geometry
-				cache.push( { primitive: primitive, promise: geometryPromise } );
+				cache[ cacheKey ] = { primitive: primitive, promise: geometryPromise };
 
 				pending.push( geometryPromise );
 
@@ -2576,7 +2566,8 @@ THREE.GLTFLoader = ( function () {
 
 				// See if we've already created this combined geometry
 				var cache = parser.multiPassGeometryCache;
-				var cached = getCachedMultiPassGeometry( cache, baseGeometry, originalPrimitives );
+				var cacheKey = createMultiPassGeometryKey( baseGeometry, originalPrimitives );
+				var cached = cache[ cacheKey ];
 
 				if ( cached !== null ) return [ cached.geometry ];
 
@@ -2617,7 +2608,7 @@ THREE.GLTFLoader = ( function () {
 
 					geometry.setIndex( indices );
 
-					cache.push( { geometry: geometry, baseGeometry: baseGeometry, primitives: originalPrimitives } );
+					cache[ cacheKey ] = { geometry: geometry, baseGeometry: baseGeometry, primitives: originalPrimitives };
 
 					return [ geometry ];
 
@@ -2636,7 +2627,8 @@ THREE.GLTFLoader = ( function () {
 
 				// See if we've already created this combined geometry
 				var cache = parser.multiplePrimitivesCache;
-				var cached = getCachedCombinedGeometry( cache, geometries );
+				var cacheKey = createArrayKeyBufferGeometry( geometries );
+				var cached = cache[ cacheKey ];
 
 				if ( cached ) {
 
@@ -2646,7 +2638,7 @@ THREE.GLTFLoader = ( function () {
 
 					var geometry = THREE.BufferGeometryUtils.mergeBufferGeometries( geometries, true );
 
-					cache.push( { geometry: geometry, baseGeometries: geometries } );
+					cache[ cacheKey ] = { geometry: geometry, baseGeometries: geometries };
 
 					if ( geometry !== null ) return [ geometry ];
 
@@ -3335,7 +3327,7 @@ THREE.GLTFLoader = ( function () {
 
 						mesh.bind( new THREE.Skeleton( bones, boneInverses ), mesh.matrixWorld );
 
-					};
+					}
 
 					return node;