提交 2f587e67 编写于 作者: M Mr.doob 提交者: GitHub

Merge pull request #10964 from donmccurdy/feat-gltf2-binary

[glTF] Update binary (.GLB) parsing for glTF 2.0.
...@@ -55,7 +55,7 @@ THREE.GLTF2Loader = ( function () { ...@@ -55,7 +55,7 @@ THREE.GLTF2Loader = ( function () {
var magic = convertUint8ArrayToString( new Uint8Array( data, 0, 4 ) ); 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 ); extensions[ EXTENSIONS.KHR_BINARY_GLTF ] = new GLTFBinaryExtension( data );
content = extensions[ EXTENSIONS.KHR_BINARY_GLTF ].content; content = extensions[ EXTENSIONS.KHR_BINARY_GLTF ].content;
...@@ -320,63 +320,70 @@ THREE.GLTF2Loader = ( function () { ...@@ -320,63 +320,70 @@ THREE.GLTF2Loader = ( function () {
/* BINARY EXTENSION */ /* BINARY EXTENSION */
var BINARY_EXTENSION_BUFFER_NAME = 'binary_glTF'; var BINARY_EXTENSION_BUFFER_NAME = 'binary_glTF';
var BINARY_EXTENSION_HEADER_MAGIC = 'glTF';
var BINARY_EXTENSION_HEADER_DEFAULTS = { magic: 'glTF', version: 1, contentFormat: 0 }; var BINARY_EXTENSION_HEADER_LENGTH = 12;
var BINARY_EXTENSION_CHUNK_TYPES = { JSON: 0x4E4F534A, BIN: 0x004E4942 };
var BINARY_EXTENSION_HEADER_LENGTH = 20;
function GLTFBinaryExtension( data ) { function GLTFBinaryExtension( data ) {
this.name = EXTENSIONS.KHR_BINARY_GLTF; this.name = EXTENSIONS.KHR_BINARY_GLTF;
this.content = null;
this.body = null;
var headerView = new DataView( data, 0, BINARY_EXTENSION_HEADER_LENGTH ); var headerView = new DataView( data, 0, BINARY_EXTENSION_HEADER_LENGTH );
var header = { this.header = {
magic: convertUint8ArrayToString( new Uint8Array( data.slice( 0, 4 ) ) ), magic: convertUint8ArrayToString( new Uint8Array( data.slice( 0, 4 ) ) ),
version: headerView.getUint32( 4, true ), version: headerView.getUint32( 4, true ),
length: headerView.getUint32( 8, true ), length: headerView.getUint32( 8, true )
contentLength: headerView.getUint32( 12, true ),
contentFormat: headerView.getUint32( 16, true )
}; };
for ( var key in BINARY_EXTENSION_HEADER_DEFAULTS ) { if ( this.header.magic !== BINARY_EXTENSION_HEADER_MAGIC ) {
var value = BINARY_EXTENSION_HEADER_DEFAULTS[ key ]; throw new Error( 'GLTF2Loader: Unsupported glTF-Binary header.' );
if ( header[ key ] !== value ) { } else if ( this.header.version < 2.0 ) {
throw new Error( 'Unsupported glTF-Binary header: Expected "%s" to be "%s".', key, value ); 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; while ( chunkIndex < chunkView.byteLength ) {
this.content = convertUint8ArrayToString( contentArray );
this.body = data.slice( BINARY_EXTENSION_HEADER_LENGTH + header.contentLength, header.length );
} 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 ]; if ( chunkType === BINARY_EXTENSION_CHUNK_TYPES.JSON ) {
var array = new Uint8Array( bufferView );
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 ************/ /********** INTERNALS ************/
...@@ -633,6 +640,13 @@ THREE.GLTF2Loader = ( function () { ...@@ -633,6 +640,13 @@ THREE.GLTF2Loader = ( function () {
} }
// Blob URL
if ( /^blob:.*$/i.test( url ) ) {
return url;
}
// Relative URL // Relative URL
return ( path || '' ) + url; return ( path || '' ) + url;
...@@ -894,7 +908,6 @@ THREE.GLTF2Loader = ( function () { ...@@ -894,7 +908,6 @@ THREE.GLTF2Loader = ( function () {
GLTFParser.prototype.loadShaders = function () { GLTFParser.prototype.loadShaders = function () {
var json = this.json; var json = this.json;
var extensions = this.extensions;
var options = this.options; var options = this.options;
return this._withDependencies( [ return this._withDependencies( [
...@@ -905,9 +918,11 @@ THREE.GLTF2Loader = ( function () { ...@@ -905,9 +918,11 @@ THREE.GLTF2Loader = ( function () {
return _each( json.shaders, function ( shader ) { 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 +952,14 @@ THREE.GLTF2Loader = ( function () { ...@@ -937,13 +952,14 @@ THREE.GLTF2Loader = ( function () {
return _each( json.buffers, function ( buffer, name ) { 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 ) { return new Promise( function ( resolve ) {
...@@ -1011,11 +1027,13 @@ THREE.GLTF2Loader = ( function () { ...@@ -1011,11 +1027,13 @@ THREE.GLTF2Loader = ( function () {
var elementBytes = TypedArray.BYTES_PER_ELEMENT; var elementBytes = TypedArray.BYTES_PER_ELEMENT;
var itemBytes = elementBytes * itemSize; var itemBytes = elementBytes * itemSize;
var array;
// The buffer is not interleaved if the stride is the item size in bytes. // The buffer is not interleaved if the stride is the item size in bytes.
if ( accessor.byteStride && accessor.byteStride !== itemBytes ) { if ( accessor.byteStride && accessor.byteStride !== itemBytes ) {
// Use the full buffer if it's interleaved. // 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. // Integer parameters to IB/IBA are in array elements, not bytes.
var ib = new THREE.InterleavedBuffer( array, accessor.byteStride / elementBytes ); var ib = new THREE.InterleavedBuffer( array, accessor.byteStride / elementBytes );
...@@ -1039,7 +1057,6 @@ THREE.GLTF2Loader = ( function () { ...@@ -1039,7 +1057,6 @@ THREE.GLTF2Loader = ( function () {
GLTFParser.prototype.loadTextures = function () { GLTFParser.prototype.loadTextures = function () {
var json = this.json; var json = this.json;
var extensions = this.extensions;
var options = this.options; var options = this.options;
return this._withDependencies( [ return this._withDependencies( [
...@@ -1057,9 +1074,14 @@ THREE.GLTF2Loader = ( function () { ...@@ -1057,9 +1074,14 @@ THREE.GLTF2Loader = ( function () {
var source = json.images[ texture.source ]; var source = json.images[ texture.source ];
var sourceUri = source.uri; var sourceUri = source.uri;
if ( source.extensions && source.extensions[ EXTENSIONS.KHR_BINARY_GLTF ] ) { var urlCreator;
if ( source.bufferView !== undefined ) {
sourceUri = extensions[ EXTENSIONS.KHR_BINARY_GLTF ].loadTextureSourceUri( source, dependencies.bufferViews ); var bufferView = dependencies.bufferViews[ source.bufferView ];
var blob = new Blob( [ bufferView ], { type: source.mimeType } );
urlCreator = window.URL || window.webkitURL;
sourceUri = urlCreator.createObjectURL( blob );
} }
...@@ -1075,6 +1097,12 @@ THREE.GLTF2Loader = ( function () { ...@@ -1075,6 +1097,12 @@ THREE.GLTF2Loader = ( function () {
textureLoader.load( resolveURL( sourceUri, options.path ), function ( _texture ) { textureLoader.load( resolveURL( sourceUri, options.path ), function ( _texture ) {
if ( urlCreator !== undefined ) {
urlCreator.revokeObjectURL( sourceUri );
}
_texture.flipY = false; _texture.flipY = false;
if ( texture.name !== undefined ) _texture.name = texture.name; if ( texture.name !== undefined ) _texture.name = texture.name;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册