Просмотр исходного кода

USDZLoader: Add `onLoad()` and `onError()` to `parse()`. (#33582)

Michael Herzog 2 месяцев назад
Родитель
Сommit
78101ea2f1
3 измененных файлов с 66 добавлено и 21 удалено
  1. 5 3
      editor/js/Loader.js
  2. 26 6
      examples/jsm/loaders/USDLoader.js
  3. 35 12
      examples/jsm/loaders/usd/USDComposer.js

+ 5 - 3
editor/js/Loader.js

@@ -780,10 +780,12 @@ function Loader( editor ) {
 					const { USDLoader } = await import( 'three/addons/loaders/USDLoader.js' );
 
 					const loader = new USDLoader( manager );
-					const group = loader.parse( contents );
-					group.name = filename;
+					loader.parse( contents, function ( group ) {
 
-					editor.execute( new AddObjectCommand( editor, group ) );
+						group.name = filename;
+						editor.execute( new AddObjectCommand( editor, group ) );
+
+					} );
 
 				}, false );
 				reader.readAsArrayBuffer( file );

+ 26 - 6
examples/jsm/loaders/USDLoader.js

@@ -58,7 +58,7 @@ class USDLoader extends Loader {
 
 			try {
 
-				onLoad( scope.parse( text ) );
+				scope.parse( text, onLoad, onError );
 
 			} catch ( e ) {
 
@@ -83,10 +83,16 @@ class USDLoader extends Loader {
 	/**
 	 * Parses the given USDZ data and returns the resulting group.
 	 *
+	 * The returned group is created synchronously, but any referenced textures
+	 * are loaded asynchronously. Provide `onLoad` to be notified once all
+	 * textures have finished loading.
+	 *
 	 * @param {ArrayBuffer|string} buffer - The raw USDZ data as an array buffer.
+	 * @param {function(Group)} [onLoad] - Executed once the group and all of its textures are ready.
+	 * @param {onErrorCallback} [onError] - Executed when errors occur.
 	 * @return {Group} The parsed asset as a group.
 	 */
-	parse( buffer ) {
+	parse( buffer, onLoad, onError ) {
 
 		const usda = new USDAParser();
 		const usdc = new USDCParser();
@@ -217,13 +223,27 @@ class USDLoader extends Loader {
 
 		const scope = this;
 
+		const finalize = ( composer, group ) => {
+
+			if ( onLoad ) {
+
+				Promise.all( composer.texturePromises )
+					.then( () => onLoad( group ) )
+					.catch( ( err ) => onError ? onError( err ) : console.error( err ) );
+
+			}
+
+			return group;
+
+		};
+
 		// USDA (standalone)
 
 		if ( typeof buffer === 'string' ) {
 
 			const composer = new USDComposer( scope.manager );
 			const data = usda.parseData( buffer );
-			return composer.compose( data, {} );
+			return finalize( composer, composer.compose( data, {} ) );
 
 		}
 
@@ -233,7 +253,7 @@ class USDLoader extends Loader {
 
 			const composer = new USDComposer( scope.manager );
 			const data = usdc.parseData( toArrayBuffer( buffer ) );
-			return composer.compose( data, {} );
+			return finalize( composer, composer.compose( data, {} ) );
 
 		}
 
@@ -261,7 +281,7 @@ class USDLoader extends Loader {
 
 			}
 
-			return composer.compose( data, assets, {}, basePath );
+			return finalize( composer, composer.compose( data, assets, {}, basePath ) );
 
 		}
 
@@ -270,7 +290,7 @@ class USDLoader extends Loader {
 		const composer = new USDComposer( scope.manager );
 		const text = textDecoder.decode( bytes );
 		const data = usda.parseData( text );
-		return composer.compose( data, {} );
+		return finalize( composer, composer.compose( data, {} ) );
 
 	}
 

+ 35 - 12
examples/jsm/loaders/usd/USDComposer.js

@@ -83,6 +83,7 @@ class USDComposer {
 		this.textureCache = {};
 		this.skinnedMeshes = [];
 		this.manager = manager;
+		this.texturePromises = [];
 
 	}
 
@@ -102,6 +103,7 @@ class USDComposer {
 		this.basePath = basePath;
 		this.skinnedMeshes = [];
 		this.skeletons = {};
+		this.texturePromises = [];
 
 		// Build indexes for O(1) lookups
 		this._buildIndexes();
@@ -3864,27 +3866,48 @@ class USDComposer {
 		}
 
 		const image = new Image();
-		image.onload = function () {
 
-			texture.image = image;
+		this.texturePromises.push( new Promise( ( resolve ) => {
 
-			if ( textureAttrs ) {
+			image.onload = function () {
 
-				texture.wrapS = scope._getWrapMode( textureAttrs[ 'inputs:wrapS' ] );
-				texture.wrapT = scope._getWrapMode( textureAttrs[ 'inputs:wrapT' ] );
+				texture.image = image;
 
-			}
+				if ( textureAttrs ) {
 
-			scope._applyTextureTransforms( texture, transformAttrs );
-			texture.needsUpdate = true;
+					texture.wrapS = scope._getWrapMode( textureAttrs[ 'inputs:wrapS' ] );
+					texture.wrapT = scope._getWrapMode( textureAttrs[ 'inputs:wrapT' ] );
 
-			if ( typeof data !== 'string' ) {
+				}
 
-				URL.revokeObjectURL( url );
+				scope._applyTextureTransforms( texture, transformAttrs );
+				texture.needsUpdate = true;
 
-			}
+				if ( typeof data !== 'string' ) {
 
-		};
+					URL.revokeObjectURL( url );
+
+				}
+
+				resolve();
+
+			};
+
+			image.onerror = function () {
+
+				console.warn( 'USDLoader: Failed to load texture:', url );
+
+				if ( typeof data !== 'string' ) {
+
+					URL.revokeObjectURL( url );
+
+				}
+
+				resolve();
+
+			};
+
+		} ) );
 
 		image.src = url;
 

粤ICP备19079148号