Browse Source

Update binary implementation for glTF 2.0.

Don McCurdy 8 years ago
parent
commit
24f2f9e249
2 changed files with 55 additions and 44 deletions
  1. 54 42
      examples/js/loaders/GLTF2Loader.js
  2. 1 2
      examples/webgl_loader_gltf.html

+ 54 - 42
examples/js/loaders/GLTF2Loader.js

@@ -55,7 +55,7 @@ THREE.GLTF2Loader = ( function () {
 
 			var magic = convertUint8ArrayToString( new Uint8Array( data, 0, 4 ) );
 
-			if ( magic === BINARY_EXTENSION_HEADER_DEFAULTS.magic ) {
+			if ( magic === BINARY_EXTENSION_HEADER_MAGIC ) {
 
 				extensions[ EXTENSIONS.KHR_BINARY_GLTF ] = new GLTFBinaryExtension( data );
 				content = extensions[ EXTENSIONS.KHR_BINARY_GLTF ].content;
@@ -320,63 +320,70 @@ THREE.GLTF2Loader = ( function () {
 	/* BINARY EXTENSION */
 
 	var BINARY_EXTENSION_BUFFER_NAME = 'binary_glTF';
-
-	var BINARY_EXTENSION_HEADER_DEFAULTS = { magic: 'glTF', version: 1, contentFormat: 0 };
-
-	var BINARY_EXTENSION_HEADER_LENGTH = 20;
+	var BINARY_EXTENSION_HEADER_MAGIC = 'glTF';
+	var BINARY_EXTENSION_HEADER_LENGTH = 12;
+	var BINARY_EXTENSION_CHUNK_TYPES = { JSON: 0x4E4F534A, BIN: 0x004E4942 };
 
 	function GLTFBinaryExtension( data ) {
 
 		this.name = EXTENSIONS.KHR_BINARY_GLTF;
+		this.content = null;
+		this.body = null;
 
 		var headerView = new DataView( data, 0, BINARY_EXTENSION_HEADER_LENGTH );
 
-		var header = {
+		this.header = {
 			magic: convertUint8ArrayToString( new Uint8Array( data.slice( 0, 4 ) ) ),
 			version: headerView.getUint32( 4, true ),
-			length: headerView.getUint32( 8, true ),
-			contentLength: headerView.getUint32( 12, true ),
-			contentFormat: headerView.getUint32( 16, true )
+			length: headerView.getUint32( 8, true )
 		};
 
-		for ( var key in BINARY_EXTENSION_HEADER_DEFAULTS ) {
-
-			var value = BINARY_EXTENSION_HEADER_DEFAULTS[ key ];
+		if ( this.header.magic !== BINARY_EXTENSION_HEADER_MAGIC ) {
 
-			if ( header[ key ] !== value ) {
+			throw new Error( 'GLTF2Loader: Unsupported glTF-Binary header.' );
 
-				throw new Error( 'Unsupported glTF-Binary header: Expected "%s" to be "%s".', key, value );
+		} else if ( this.header.version < 2.0 ) {
 
-			}
+			throw new Error( 'GLTF2Loader: Legacy binary file detected. Use GLTFLoader instead.' );
 
 		}
 
-		var contentArray = new Uint8Array( data, BINARY_EXTENSION_HEADER_LENGTH, header.contentLength );
+		var chunkView = new DataView( data, BINARY_EXTENSION_HEADER_LENGTH );
+		var chunkIndex = 0;
 
-		this.header = header;
-		this.content = convertUint8ArrayToString( contentArray );
-		this.body = data.slice( BINARY_EXTENSION_HEADER_LENGTH + header.contentLength, header.length );
+		while ( chunkIndex < chunkView.byteLength ) {
 
-	}
+			var chunkLength = chunkView.getUint32( chunkIndex, true );
+			chunkIndex += 4;
 
-	GLTFBinaryExtension.prototype.loadShader = function ( shader, bufferViews ) {
+			var chunkType = chunkView.getUint32( chunkIndex, true );
+			chunkIndex += 4;
 
-		var bufferView = bufferViews[ shader.extensions[ EXTENSIONS.KHR_BINARY_GLTF ].bufferView ];
-		var array = new Uint8Array( bufferView );
+			if ( chunkType === BINARY_EXTENSION_CHUNK_TYPES.JSON ) {
 
-		return convertUint8ArrayToString( array );
+				var contentArray = new Uint8Array( data, BINARY_EXTENSION_HEADER_LENGTH + chunkIndex, chunkLength );
+				this.content = convertUint8ArrayToString( contentArray );
 
-	};
+			} else if ( chunkType === BINARY_EXTENSION_CHUNK_TYPES.BIN ) {
 
-	GLTFBinaryExtension.prototype.loadTextureSourceUri = function ( source, bufferViews ) {
+				var byteOffset = BINARY_EXTENSION_HEADER_LENGTH + chunkIndex;
+				this.body = data.slice( byteOffset, byteOffset + chunkLength );
 
-		var metadata = source.extensions[ EXTENSIONS.KHR_BINARY_GLTF ];
-		var bufferView = bufferViews[ metadata.bufferView ];
-		var stringData = convertUint8ArrayToString( new Uint8Array( bufferView ) );
+			}
 
-		return 'data:' + metadata.mimeType + ';base64,' + btoa( stringData );
+			// Clients must ignore chunks with unknown types.
 
-	};
+			chunkIndex += chunkLength;
+
+		}
+
+		if ( this.content === null ) {
+
+			throw new Error( 'GLTF2Loader: JSON content not found.' );
+
+		}
+
+	}
 
 	/*********************************/
 	/********** INTERNALS ************/
@@ -894,7 +901,6 @@ THREE.GLTF2Loader = ( function () {
 	GLTFParser.prototype.loadShaders = function () {
 
 		var json = this.json;
-		var extensions = this.extensions;
 		var options = this.options;
 
 		return this._withDependencies( [
@@ -905,9 +911,11 @@ THREE.GLTF2Loader = ( function () {
 
 			return _each( json.shaders, function ( shader ) {
 
-				if ( shader.extensions && shader.extensions[ EXTENSIONS.KHR_BINARY_GLTF ] ) {
+				if ( shader.bufferView !== undefined ) {
 
-					return extensions[ EXTENSIONS.KHR_BINARY_GLTF ].loadShader( shader, dependencies.bufferViews );
+					var bufferView = dependencies.bufferViews[ shader.bufferView ];
+					var array = new Uint8Array( bufferView );
+					return convertUint8ArrayToString( array );
 
 				}
 
@@ -937,13 +945,14 @@ THREE.GLTF2Loader = ( function () {
 
 		return _each( json.buffers, function ( buffer, name ) {
 
-			if ( name === BINARY_EXTENSION_BUFFER_NAME ) {
+			if ( buffer.type === 'arraybuffer' || buffer.type === undefined ) {
 
-				return extensions[ EXTENSIONS.KHR_BINARY_GLTF ].body;
+				// If present, GLB container is required to be the first buffer.
+				if ( buffer.uri === undefined && name === 0 ) {
 
-			}
+					return extensions[ EXTENSIONS.KHR_BINARY_GLTF ].body;
 
-			if ( buffer.type === 'arraybuffer' || buffer.type === undefined ) {
+				}
 
 				return new Promise( function ( resolve ) {
 
@@ -1011,11 +1020,13 @@ THREE.GLTF2Loader = ( function () {
 				var elementBytes = TypedArray.BYTES_PER_ELEMENT;
 				var itemBytes = elementBytes * itemSize;
 
+				var array;
+
 				// The buffer is not interleaved if the stride is the item size in bytes.
 				if ( accessor.byteStride && accessor.byteStride !== itemBytes ) {
 
 					// Use the full buffer if it's interleaved.
-					var array = new TypedArray( arraybuffer );
+					array = new TypedArray( arraybuffer );
 
 					// Integer parameters to IB/IBA are in array elements, not bytes.
 					var ib = new THREE.InterleavedBuffer( array, accessor.byteStride / elementBytes );
@@ -1039,7 +1050,6 @@ THREE.GLTF2Loader = ( function () {
 	GLTFParser.prototype.loadTextures = function () {
 
 		var json = this.json;
-		var extensions = this.extensions;
 		var options = this.options;
 
 		return this._withDependencies( [
@@ -1057,9 +1067,11 @@ THREE.GLTF2Loader = ( function () {
 						var source = json.images[ texture.source ];
 						var sourceUri = source.uri;
 
-						if ( source.extensions && source.extensions[ EXTENSIONS.KHR_BINARY_GLTF ] ) {
+						if ( source.bufferView !== undefined ) {
 
-							sourceUri = extensions[ EXTENSIONS.KHR_BINARY_GLTF ].loadTextureSourceUri( source, dependencies.bufferViews );
+							var bufferView = dependencies.bufferViews[ source.bufferView ];
+							var stringData = convertUint8ArrayToString( new Uint8Array( bufferView ) );
+							sourceUri = 'data:' + source.mimeType + ';base64,' + btoa( stringData );
 
 						}
 

+ 1 - 2
examples/webgl_loader_gltf.html

@@ -387,9 +387,8 @@
 					cameraPos: new THREE.Vector3(2, 1, 3),
 					objectRotation: new THREE.Euler(0, Math.PI, 0),
 					addLights:true,
-					extensions: ["glTF"]
+					extensions: ["glTF", "glTF-Binary"]
 				},
-
 				{
 					name : "Duck", url : "./models/gltf/duck/%s/duck.gltf",
 					cameraPos: new THREE.Vector3(0, 3, 5),