Pārlūkot izejas kodu

GLTFExporter: add onError parameter to parse (#22774)

* GLTFExporter: add onError parameter to parse

* GLTFExporter: fix syntax error

* GLTFExporter: add documentation and warning about the onError parameter

Co-authored-by: Michael Herzog <[email protected]>
Marco Fugaro 3 gadi atpakaļ
vecāks
revīzija
429b3d3f6e

+ 20 - 5
docs/examples/en/exporters/GLTFExporter.html

@@ -48,10 +48,23 @@
 		const exporter = new GLTFExporter();
 
 		// Parse the input and generate the glTF output
-		exporter.parse( scene, function ( gltf ) {
-			console.log( gltf );
-			downloadJSON( gltf );
-		}, options );
+		exporter.parse(
+			scene,
+			// called when the gltf has been generated
+			function ( gltf ) {
+
+				console.log( gltf );
+				downloadJSON( gltf );
+
+			},
+			// called when there is an error in the generation
+			function ( error ) {
+
+				console.log( 'An error happened' );
+
+			},
+			options
+		);
 		</code>
 
 		<h2>Examples</h2>
@@ -71,7 +84,8 @@
 
 		<h2>Methods</h2>
 
-		<h3>[method:undefined parse]( [param:Object3D input], [param:Function onCompleted], [param:Object options] )</h3>
+		<h3>[method:undefined parse]( [param:Object3D input], [param:Function onCompleted], [param:Function onError], [param:Object options] )</h3>
+
 		<p>
 		[page:Object input] — Scenes or objects to export. Valid options:<br />
 		<ul>
@@ -98,6 +112,7 @@
 		</ul>
 
 		[page:Function onCompleted] — Will be called when the export completes. The argument will be the generated glTF JSON or binary ArrayBuffer.<br />
+		[page:Function onError] — Will be called if there are any errors during the gltf generation.<br />
 		[page:Options options] — Export options<br />
 		<ul>
 			<li>trs - bool. Export position, rotation and scale instead of matrix per node. Default is false</li>

+ 20 - 5
docs/examples/zh/exporters/GLTFExporter.html

@@ -48,10 +48,23 @@
 		const exporter = new GLTFExporter();
 
 		// Parse the input and generate the glTF output
-		exporter.parse( scene, function ( gltf ) {
-			console.log( gltf );
-			downloadJSON( gltf );
-		}, options );
+		exporter.parse(
+			scene,
+			// called when the gltf has been generated
+			function ( gltf ) {
+
+				console.log( gltf );
+				downloadJSON( gltf );
+
+			},
+			// called when there is an error in the generation
+			function ( error ) {
+
+				console.log( 'An error happened' );
+
+			},
+			options
+		);
 		</code>
 
 		<h2>例子</h2>
@@ -71,7 +84,8 @@
 
 		<h2>Methods</h2>
 
-		<h3>[method:undefined parse]( [param:Object3D input], [param:Function onCompleted], [param:Object options] )</h3>
+		<h3>[method:undefined parse]( [param:Object3D input], [param:Function onCompleted], [param:Function onError], [param:Object options] )</h3>
+
 		<p>
 		[page:Object input] — Scenes or objects to export. Valid options:<br />
 		<ul>
@@ -98,6 +112,7 @@
 		</ul>
 
 		[page:Function onCompleted] — Will be called when the export completes. The argument will be the generated glTF JSON or binary ArrayBuffer.<br />
+		[page:Function onError] — Will be called if there are any errors during the gltf generation.<br />
 		[page:Options options] — Export options<br />
 		<ul>
 			<li>trs - bool. Export position, rotation and scale instead of matrix per node. Default is false</li>

+ 80 - 81
examples/jsm/exporters/GLTFExporter.js

@@ -94,9 +94,18 @@ class GLTFExporter {
 	 * Parse scenes and generate GLTF output
 	 * @param  {Scene or [THREE.Scenes]} input   Scene or Array of THREE.Scenes
 	 * @param  {Function} onDone  Callback on completed
+	 * @param  {Function} onError  Callback on errors
 	 * @param  {Object} options options
 	 */
-	parse( input, onDone, options ) {
+	parse( input, onDone, onError, options ) {
+
+		if ( typeof onError === 'object' ) {
+
+			console.warn( 'THREE.GLTFExporter: parse() expects options as the fourth argument now.' );
+
+			options = onError;
+
+		}
 
 		const writer = new GLTFWriter();
 		const plugins = [];
@@ -108,7 +117,7 @@ class GLTFExporter {
 		}
 
 		writer.setPlugins( plugins );
-		writer.write( input, onDone, options );
+		writer.write( input, onDone, options ).catch( onError );
 
 	}
 
@@ -118,15 +127,7 @@ class GLTFExporter {
 
 		return new Promise( function ( resolve, reject ) {
 
-			try {
-
-				scope.parse( input, resolve, options );
-
-			} catch ( e ) {
-
-				reject( e );
-
-			}
+			scope.parse( input, resolve, reject, options );
 
 		} );
 
@@ -407,7 +408,7 @@ class GLTFWriter {
 	 * @param  {Function} onDone  Callback on completed
 	 * @param  {Object} options options
 	 */
-	write( input, onDone, options ) {
+	async write( input, onDone, options ) {
 
 		this.options = Object.assign( {}, {
 			// default options
@@ -430,97 +431,95 @@ class GLTFWriter {
 
 		this.processInput( input );
 
-		const writer = this;
-
-		Promise.all( this.pending ).then( function () {
+		await Promise.all( this.pending );
 
-			const buffers = writer.buffers;
-			const json = writer.json;
-			const options = writer.options;
-			const extensionsUsed = writer.extensionsUsed;
+		const writer = this;
+		const buffers = writer.buffers;
+		const json = writer.json;
+		options = writer.options;
+		const extensionsUsed = writer.extensionsUsed;
 
-			// Merge buffers.
-			const blob = new Blob( buffers, { type: 'application/octet-stream' } );
+		// Merge buffers.
+		const blob = new Blob( buffers, { type: 'application/octet-stream' } );
 
-			// Declare extensions.
-			const extensionsUsedList = Object.keys( extensionsUsed );
+		// Declare extensions.
+		const extensionsUsedList = Object.keys( extensionsUsed );
 
-			if ( extensionsUsedList.length > 0 ) json.extensionsUsed = extensionsUsedList;
+		if ( extensionsUsedList.length > 0 ) json.extensionsUsed = extensionsUsedList;
 
-			// Update bytelength of the single buffer.
-			if ( json.buffers && json.buffers.length > 0 ) json.buffers[ 0 ].byteLength = blob.size;
+		// Update bytelength of the single buffer.
+		if ( json.buffers && json.buffers.length > 0 ) json.buffers[ 0 ].byteLength = blob.size;
 
-			if ( options.binary === true ) {
+		if ( options.binary === true ) {
 
-				// https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#glb-file-format-specification
+			// https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#glb-file-format-specification
 
-				const reader = new window.FileReader();
-				reader.readAsArrayBuffer( blob );
-				reader.onloadend = function () {
+			const reader = new window.FileReader();
+			reader.readAsArrayBuffer( blob );
+			reader.onloadend = function () {
 
-					// Binary chunk.
-					const binaryChunk = getPaddedArrayBuffer( reader.result );
-					const binaryChunkPrefix = new DataView( new ArrayBuffer( GLB_CHUNK_PREFIX_BYTES ) );
-					binaryChunkPrefix.setUint32( 0, binaryChunk.byteLength, true );
-					binaryChunkPrefix.setUint32( 4, GLB_CHUNK_TYPE_BIN, true );
-
-					// JSON chunk.
-					const jsonChunk = getPaddedArrayBuffer( stringToArrayBuffer( JSON.stringify( json ) ), 0x20 );
-					const jsonChunkPrefix = new DataView( new ArrayBuffer( GLB_CHUNK_PREFIX_BYTES ) );
-					jsonChunkPrefix.setUint32( 0, jsonChunk.byteLength, true );
-					jsonChunkPrefix.setUint32( 4, GLB_CHUNK_TYPE_JSON, true );
-
-					// GLB header.
-					const header = new ArrayBuffer( GLB_HEADER_BYTES );
-					const headerView = new DataView( header );
-					headerView.setUint32( 0, GLB_HEADER_MAGIC, true );
-					headerView.setUint32( 4, GLB_VERSION, true );
-					const totalByteLength = GLB_HEADER_BYTES
-						+ jsonChunkPrefix.byteLength + jsonChunk.byteLength
-						+ binaryChunkPrefix.byteLength + binaryChunk.byteLength;
-					headerView.setUint32( 8, totalByteLength, true );
-
-					const glbBlob = new Blob( [
-						header,
-						jsonChunkPrefix,
-						jsonChunk,
-						binaryChunkPrefix,
-						binaryChunk
-					], { type: 'application/octet-stream' } );
-
-					const glbReader = new window.FileReader();
-					glbReader.readAsArrayBuffer( glbBlob );
-					glbReader.onloadend = function () {
-
-						onDone( glbReader.result );
-
-					};
+				// Binary chunk.
+				const binaryChunk = getPaddedArrayBuffer( reader.result );
+				const binaryChunkPrefix = new DataView( new ArrayBuffer( GLB_CHUNK_PREFIX_BYTES ) );
+				binaryChunkPrefix.setUint32( 0, binaryChunk.byteLength, true );
+				binaryChunkPrefix.setUint32( 4, GLB_CHUNK_TYPE_BIN, true );
+
+				// JSON chunk.
+				const jsonChunk = getPaddedArrayBuffer( stringToArrayBuffer( JSON.stringify( json ) ), 0x20 );
+				const jsonChunkPrefix = new DataView( new ArrayBuffer( GLB_CHUNK_PREFIX_BYTES ) );
+				jsonChunkPrefix.setUint32( 0, jsonChunk.byteLength, true );
+				jsonChunkPrefix.setUint32( 4, GLB_CHUNK_TYPE_JSON, true );
+
+				// GLB header.
+				const header = new ArrayBuffer( GLB_HEADER_BYTES );
+				const headerView = new DataView( header );
+				headerView.setUint32( 0, GLB_HEADER_MAGIC, true );
+				headerView.setUint32( 4, GLB_VERSION, true );
+				const totalByteLength = GLB_HEADER_BYTES
+					+ jsonChunkPrefix.byteLength + jsonChunk.byteLength
+					+ binaryChunkPrefix.byteLength + binaryChunk.byteLength;
+				headerView.setUint32( 8, totalByteLength, true );
+
+				const glbBlob = new Blob( [
+					header,
+					jsonChunkPrefix,
+					jsonChunk,
+					binaryChunkPrefix,
+					binaryChunk
+				], { type: 'application/octet-stream' } );
+
+				const glbReader = new window.FileReader();
+				glbReader.readAsArrayBuffer( glbBlob );
+				glbReader.onloadend = function () {
+
+					onDone( glbReader.result );
 
 				};
 
-			} else {
+			};
 
-				if ( json.buffers && json.buffers.length > 0 ) {
+		} else {
 
-					const reader = new window.FileReader();
-					reader.readAsDataURL( blob );
-					reader.onloadend = function () {
+			if ( json.buffers && json.buffers.length > 0 ) {
 
-						const base64data = reader.result;
-						json.buffers[ 0 ].uri = base64data;
-						onDone( json );
+				const reader = new window.FileReader();
+				reader.readAsDataURL( blob );
+				reader.onloadend = function () {
 
-					};
+					const base64data = reader.result;
+					json.buffers[ 0 ].uri = base64data;
+					onDone( json );
 
-				} else {
+				};
 
-					onDone( json );
+			} else {
 
-				}
+				onDone( json );
 
 			}
 
-		} );
+		}
+
 
 	}
 

+ 32 - 23
examples/misc_exporter_gltf.html

@@ -41,21 +41,30 @@
 					binary: document.getElementById( 'option_binary' ).checked,
 					maxTextureSize: Number( document.getElementById( 'option_maxsize' ).value ) || Infinity // To prevent NaN value
 				};
-				gltfExporter.parse( input, function ( result ) {
+				gltfExporter.parse(
+					input,
+					function ( result ) {
 
-					if ( result instanceof ArrayBuffer ) {
+						if ( result instanceof ArrayBuffer ) {
 
-						saveArrayBuffer( result, 'scene.glb' );
+							saveArrayBuffer( result, 'scene.glb' );
 
-					} else {
+						} else {
 
-						const output = JSON.stringify( result, null, 2 );
-						console.log( output );
-						saveString( output, 'scene.gltf' );
+							const output = JSON.stringify( result, null, 2 );
+							console.log( output );
+							saveString( output, 'scene.gltf' );
 
-					}
+						}
+
+					},
+					function ( error ) {
+
+						console.log( 'An error happened during parsing', error );
 
-				}, options );
+					},
+					options
+				);
 
 			}
 
@@ -162,7 +171,7 @@
 				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 2000 );
 				camera.position.set( 600, 400, 0 );
 
-				camera.name = "PerspectiveCamera";
+				camera.name = 'PerspectiveCamera';
 				scene1.add( camera );
 
 				// ---------------------------------------------------------------------
@@ -187,14 +196,14 @@
 				// ---------------------------------------------------------------------
 				gridHelper = new THREE.GridHelper( 2000, 20, 0x888888, 0x444444 );
 				gridHelper.position.y = - 50;
-				gridHelper.name = "Grid";
+				gridHelper.name = 'Grid';
 				scene1.add( gridHelper );
 
 				// ---------------------------------------------------------------------
 				// Axes
 				// ---------------------------------------------------------------------
 				const axes = new THREE.AxesHelper( 500 );
-				axes.name = "AxesHelper";
+				axes.name = 'AxesHelper';
 				scene1.add( axes );
 
 				// ---------------------------------------------------------------------
@@ -248,7 +257,7 @@
 				material.map = gradientTexture;
 				sphere = new THREE.Mesh( new THREE.SphereGeometry( 70, 10, 10 ), material );
 				sphere.position.set( 0, 0, 0 );
-				sphere.name = "Sphere";
+				sphere.name = 'Sphere';
 				scene1.add( sphere );
 
 				// Cylinder
@@ -258,7 +267,7 @@
 				} );
 				object = new THREE.Mesh( new THREE.CylinderGeometry( 10, 80, 100 ), material );
 				object.position.set( 200, 0, 0 );
-				object.name = "Cylinder";
+				object.name = 'Cylinder';
 				scene1.add( object );
 
 				// TorusKnot
@@ -268,7 +277,7 @@
 				} );
 				object = new THREE.Mesh( new THREE.TorusKnotGeometry( 50, 15, 40, 10 ), material );
 				object.position.set( - 200, 0, 0 );
-				object.name = "Cylinder";
+				object.name = 'Cylinder';
 				scene1.add( object );
 
 
@@ -280,13 +289,13 @@
 
 				object = new THREE.Mesh( new THREE.BoxGeometry( 40, 100, 100 ), material );
 				object.position.set( - 200, 0, 400 );
-				object.name = "Cube";
+				object.name = 'Cube';
 				scene1.add( object );
 
 				object2 = new THREE.Mesh( new THREE.BoxGeometry( 40, 40, 40, 2, 2, 2 ), material );
 				object2.position.set( 0, 0, 50 );
 				object2.rotation.set( 0, 45, 0 );
-				object2.name = "SubCube";
+				object2.name = 'SubCube';
 				object.add( object2 );
 
 
@@ -294,16 +303,16 @@
 				// Groups
 				// ---------------------------------------------------------------------
 				const group1 = new THREE.Group();
-				group1.name = "Group";
+				group1.name = 'Group';
 				scene1.add( group1 );
 
 				const group2 = new THREE.Group();
-				group2.name = "subGroup";
+				group2.name = 'subGroup';
 				group2.position.set( 0, 50, 0 );
 				group1.add( group2 );
 
 				object2 = new THREE.Mesh( new THREE.BoxGeometry( 30, 30, 30 ), material );
-				object2.name = "Cube in group";
+				object2.name = 'Cube in group';
 				object2.position.set( 0, 0, 400 );
 				group2.add( object2 );
 
@@ -406,7 +415,7 @@
 
 				const pointsMaterial = new THREE.PointsMaterial( { color: 0xffff00, size: 5 } );
 				const pointCloud = new THREE.Points( pointsGeo, pointsMaterial );
-				pointCloud.name = "Points";
+				pointCloud.name = 'Points';
 				pointCloud.position.set( - 200, 0, - 200 );
 				scene1.add( pointCloud );
 
@@ -455,7 +464,7 @@
 				} );
 				object = new THREE.Mesh( new THREE.BoxGeometry( 200, 200, 200 ), material );
 				object.position.set( 0, 0, 0 );
-				object.name = "CubeHidden";
+				object.name = 'CubeHidden';
 				object.visible = false;
 				scene1.add( object );
 
@@ -479,7 +488,7 @@
 				scene2 = new THREE.Scene();
 				object = new THREE.Mesh( new THREE.BoxGeometry( 100, 100, 100 ), material );
 				object.position.set( 0, 0, 0 );
-				object.name = "Cube2ndScene";
+				object.name = 'Cube2ndScene';
 				scene2.name = 'Scene2';
 				scene2.add( object );