Browse Source

GLTFExporter: Support for binary (.glb) export option.

Don McCurdy 7 năm trước cách đây
mục cha
commit
0fd4cf3571

+ 3 - 2
docs/examples/exporters/GLTFExporter.html

@@ -72,16 +72,17 @@ exporter.parse( [ scene1, object1, object2, scene2 ], ...)
 			</code>
 		</ul>
 
-		[page:Function onCompleted] — Will be called when the export completes. The argument will be the generated glTF JSON.<br />
+		[page:Function onCompleted] — Will be called when the export completes. The argument will be the generated glTF JSON or binary ArrayBuffer.<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>
 			<li>onlyVisible - bool. Export only visible objects. Default is true.</li>
 			<li>truncateDrawRange - bool. Export just the attributes within the drawRange, if defined, instead of exporting the whole array. Default is true.</li>
+			<li>binary - bool. Export in binary (.glb) format, returning an ArrayBuffer. Default is false.</li>
 		</ul>
 		</div>
 		<div>
-		Generates a glTF output (JSON) with from the input (Scene or Objects)
+		Generates a .gltf (JSON) or .glb (binary) output from the input (Scene or Objects)
 		</div>
 
 		<h2>Source</h2>

+ 95 - 7
examples/js/exporters/GLTFExporter.js

@@ -54,6 +54,7 @@ THREE.GLTFExporter.prototype = {
 	 * @param  {Function} onDone  Callback on completed
 	 * @param  {Object} options options
 	 *                          trs: Exports position, rotation and scale instead of matrix
+	 *                          binary: Exports `.glb` as ArrayBuffer, instead of `.gltf` as JSON
 	 */
 	parse: function ( input, onDone, options ) {
 
@@ -104,6 +105,33 @@ THREE.GLTFExporter.prototype = {
 
 		}
 
+		/**
+		 * Converts a string to an ArrayBuffer.
+		 * @param  {string} text
+		 * @return {ArrayBuffer}
+		 */
+		function stringToArrayBuffer( text ) {
+
+			if ( window.TextEncoder !== undefined ) {
+
+				return new TextEncoder().encode( text ).buffer;
+
+			}
+
+			var buffer = new ArrayBuffer( text.length * 2 ); // 2 bytes per character.
+
+			var bufferView = new Uint16Array( buffer );
+
+			for ( var i = 0; i < text.length; ++ i ) {
+
+				bufferView[ i ] = text.charCodeAt( i );
+
+			}
+
+			return buffer;
+
+		}
+
 		/**
 		 * Get the min and he max vectors from the given attribute
 		 * @param  {THREE.WebGLAttribute} attribute Attribute to find the min/max
@@ -1002,17 +1030,77 @@ THREE.GLTFExporter.prototype = {
 		if ( outputJSON.buffers && outputJSON.buffers.length > 0 ) {
 
 			outputJSON.buffers[ 0 ].byteLength = blob.size;
-			var objectURL = URL.createObjectURL( blob );
 
 			var reader = new window.FileReader();
-			reader.readAsDataURL( blob );
-			reader.onloadend = function () {
 
-				var base64data = reader.result;
-				outputJSON.buffers[ 0 ].uri = base64data;
-				onDone( outputJSON );
+			if ( options.binary === true ) {
+
+				// https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#glb-file-format-specification
+
+				var GLB_HEADER_BYTES = 12;
+				var GLB_HEADER_MAGIC = 0x46546C67;
+				var GLB_VERSION = 2;
+
+				var GLB_CHUNK_PREFIX_BYTES = 8;
+				var GLB_CHUNK_TYPE_JSON = 0x4E4F534A;
+				var GLB_CHUNK_TYPE_BIN = 0x004E4942;
+
+				reader.readAsArrayBuffer( blob );
+				reader.onloadend = function () {
+
+					// Binary chunk.
+					var binaryChunk = reader.result;
+					var 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.
+					delete outputJSON.buffers[ 0 ].uri; // Omitted URI indicates use of binary chunk.
+					var jsonChunk = stringToArrayBuffer( JSON.stringify( outputJSON ) );
+					var 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.
+					var header = new ArrayBuffer( GLB_HEADER_BYTES );
+					var headerView = new DataView( header );
+					headerView.setUint32( 0, GLB_HEADER_MAGIC, true );
+					headerView.setUint32( 4, GLB_VERSION, true );
+					var totalByteLength = GLB_HEADER_BYTES
+						+ jsonChunkPrefix.byteLength + jsonChunk.byteLength
+						+ binaryChunkPrefix.byteLength + binaryChunk.byteLength;
+					headerView.setUint32( 8, totalByteLength, true );
+
+					var glbBlob = new Blob( [
+						header,
+						jsonChunkPrefix,
+						jsonChunk,
+						binaryChunkPrefix,
+						binaryChunk
+					], { type: 'application/octet-stream' } );
+
+					var glbReader = new window.FileReader();
+					glbReader.readAsArrayBuffer( glbBlob );
+					glbReader.onloadend = function () {
+
+						onDone( glbReader.result );
 
-			};
+					};
+
+				};
+
+			} else {
+
+				reader.readAsDataURL( blob );
+				reader.onloadend = function () {
+
+					var base64data = reader.result;
+					outputJSON.buffers[ 0 ].uri = base64data;
+					onDone( outputJSON );
+
+				};
+
+			}
 
 		} else {
 

+ 23 - 6
examples/misc_exporter_gltf.html

@@ -32,6 +32,7 @@
 			<label><input id="option_trs" name="trs" type="checkbox"/>TRS</label>
 			<label><input id="option_visible" name="visible" type="checkbox" checked="checked"/>Only Visible</label>
 			<label><input id="option_drawrange" name="visible" type="checkbox" checked="checked"/>Truncate drawRange</label>
+			<label><input id="option_binary" name="visible" type="checkbox">Binary (<code>.glb</code>)</label>
 		</div>
 
 		<script src="../build/three.js"></script>
@@ -48,13 +49,22 @@
 				var options = {
 					trs: document.getElementById('option_trs').checked,
 					onlyVisible: document.getElementById('option_visible').checked,
-					truncateDrawRange: document.getElementById('option_drawrange').checked
-				}
+					truncateDrawRange: document.getElementById('option_drawrange').checked,
+					binary: document.getElementById('option_binary').checked
+				};
 				gltfExporter.parse( input, function( result ) {
 
-					var output = JSON.stringify( result, null, 2 );
-					console.log( output );
-					saveString( output, 'scene.gltf' );
+					if ( result instanceof ArrayBuffer ) {
+
+						saveArrayBuffer( result, 'scene.glb' );
+
+					} else {
+
+						var output = JSON.stringify( result, null, 2 );
+						console.log( output );
+						saveString( output, 'scene.gltf' );
+
+					}
 
 				}, options );
 
@@ -98,7 +108,7 @@
 			function save( blob, filename ) {
 
 				link.href = URL.createObjectURL( blob );
-				link.download = filename || 'data.json';
+				link.download = filename;
 				link.click();
 
 				// URL.revokeObjectURL( url ); breaks Firefox...
@@ -111,6 +121,13 @@
 
 			}
 
+
+			function saveArrayBuffer( buffer, filename ) {
+
+				save( new Blob( [ buffer ], { type: 'application/octet-stream' } ), filename );
+
+			}
+
 			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
 
 			var container;