提交 fef8cb07 编写于 作者: D Don McCurdy 提交者: Don McCurdy

Add support for glTF binary extension.

上级 95c35211
...@@ -24,9 +24,12 @@ THREE.GLTFLoader = ( function () { ...@@ -24,9 +24,12 @@ THREE.GLTFLoader = ( function () {
var path = this.path && ( typeof this.path === "string" ) ? this.path : THREE.Loader.prototype.extractUrlBase( url ); var path = this.path && ( typeof this.path === "string" ) ? this.path : THREE.Loader.prototype.extractUrlBase( url );
var loader = new THREE.FileLoader( scope.manager ); var loader = new THREE.FileLoader( scope.manager );
loader.load( url, function ( text ) {
scope.parse( JSON.parse( text ), onLoad, path ); loader.setResponseType( 'arraybuffer' );
loader.load( url, function ( data ) {
scope.parse( data , onLoad, path );
}, onProgress, onError ); }, onProgress, onError );
...@@ -44,11 +47,37 @@ THREE.GLTFLoader = ( function () { ...@@ -44,11 +47,37 @@ THREE.GLTFLoader = ( function () {
}, },
parse: function ( json, callback, path ) { parse: function ( data, callback, path ) {
var json;
var extensions = {};
var magic = convertUint8ArrayToString( new Uint8Array( data, 0, 4 ) );
if ( magic === BINARY_EXTENSION_HEADER_DEFAULTS.magic ) {
extensions[ EXTENSIONS.KHR_BINARY_GLTF ] = new GLTFBinaryExtension( data );
json = extensions[ EXTENSIONS.KHR_BINARY_GLTF ].content;
} else {
json = convertUint8ArrayToString( new Uint8Array( data ) );
}
json = JSON.parse( json );
if ( json.extensionsUsed && json.extensionsUsed.indexOf( EXTENSIONS.KHR_MATERIALS_COMMON ) >= 0 ) {
extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ] = new GLTFMaterialsCommonExtension( json );
}
console.time( 'GLTFLoader' ); console.time( 'GLTFLoader' );
var parser = new GLTFParser( json, { var parser = new GLTFParser( json, extensions, {
path: path || this.path, path: path || this.path,
crossOrigin: this.crossOrigin crossOrigin: this.crossOrigin
...@@ -255,6 +284,126 @@ THREE.GLTFLoader = ( function () { ...@@ -255,6 +284,126 @@ THREE.GLTFLoader = ( function () {
}; };
/*********************************/
/********** EXTENSIONS ***********/
/*********************************/
var EXTENSIONS = {
KHR_BINARY_GLTF: 'KHR_binary_glTF',
KHR_MATERIALS_COMMON: 'KHR_materials_common'
};
/* MATERIALS COMMON EXTENSION */
function GLTFMaterialsCommonExtension ( json ) {
this.name = EXTENSIONS.KHR_MATERIALS_COMMON;
this.lights = {};
var lights = json.extensions && json.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ].lights;
for ( var lightId in lights ) {
var light = lights[ lightId ];
var lightNode;
var lightParams = light[ light.type ];
var color = new THREE.Color().fromArray( lightParams.color );
switch ( light.type ) {
case "directional":
lightNode = new THREE.DirectionalLight( color );
lightNode.position.set( 0, 0, 1 );
break;
case "point":
lightNode = new THREE.PointLight( color );
break;
case "spot":
lightNode = new THREE.SpotLight( color );
lightNode.position.set( 0, 0, 1 );
break;
case "ambient":
lightNode = new THREE.AmbientLight( color );
break;
}
if ( lightNode ) {
this.lights[ lightId ] = lightNode;
}
}
}
/* 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;
function GLTFBinaryExtension ( data ) {
this.name = EXTENSIONS.KHR_BINARY_GLTF;
var headerView = new DataView( data, 0, BINARY_EXTENSION_HEADER_LENGTH );
var 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 )
};
for ( var key in BINARY_EXTENSION_HEADER_DEFAULTS ) {
var value = BINARY_EXTENSION_HEADER_DEFAULTS[ key ];
if ( header[ key ] !== value ) {
throw new Error( 'Unsupported glTF-Binary header: Expected "%s" to be "%s".', key, value );
}
}
var contentArray = new Uint8Array( data, BINARY_EXTENSION_HEADER_LENGTH, header.contentLength );
this.header = header;
this.content = convertUint8ArrayToString( contentArray );
this.body = data.slice( BINARY_EXTENSION_HEADER_LENGTH + header.contentLength, header.length );
}
GLTFBinaryExtension.prototype.loadShader = function ( shader, bufferViews ) {
var bufferView = bufferViews[ shader.extensions[ EXTENSIONS.KHR_BINARY_GLTF ].bufferView ];
var array = new Uint8Array( bufferView );
return convertUint8ArrayToString( array );
};
GLTFBinaryExtension.prototype.loadTextureSourceUri = function ( source, bufferViews ) {
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 );
};
/*********************************/ /*********************************/
/********** INTERNALS ************/ /********** INTERNALS ************/
/*********************************/ /*********************************/
...@@ -471,6 +620,20 @@ THREE.GLTFLoader = ( function () { ...@@ -471,6 +620,20 @@ THREE.GLTFLoader = ( function () {
} }
// Avoid the String.fromCharCode.apply(null, array) shortcut, which
// throws a "maximum call stack size exceeded" error for large arrays.
function convertUint8ArrayToString ( array ) {
var s = '';
for ( var i = 0; i < array.length; i++ ) {
s += String.fromCharCode( array[ i ] );
}
return s;
}
// Three.js seems too dependent on attribute names so globally // Three.js seems too dependent on attribute names so globally
// replace those in the shader code // replace those in the shader code
function replaceTHREEShaderAttributes( shaderText, technique ) { function replaceTHREEShaderAttributes( shaderText, technique ) {
...@@ -614,9 +777,10 @@ THREE.GLTFLoader = ( function () { ...@@ -614,9 +777,10 @@ THREE.GLTFLoader = ( function () {
/* GLTF PARSER */ /* GLTF PARSER */
function GLTFParser( json, options ) { function GLTFParser( json, extensions, options ) {
this.json = json || {}; this.json = json || {};
this.extensions = extensions || {};
this.options = options || {}; this.options = options || {};
// loader object cache // loader object cache
...@@ -710,10 +874,23 @@ THREE.GLTFLoader = ( function () { ...@@ -710,10 +874,23 @@ THREE.GLTFLoader = ( 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( [
"bufferViews"
] ).then( function ( dependencies ) {
return _each( json.shaders, function ( shader ) { return _each( json.shaders, function ( shader ) {
if ( shader.extensions && shader.extensions[ EXTENSIONS.KHR_BINARY_GLTF ] ) {
return extensions[ EXTENSIONS.KHR_BINARY_GLTF ].loadShader( shader, dependencies.bufferViews );
}
return new Promise( function ( resolve ) { return new Promise( function ( resolve ) {
var loader = new THREE.FileLoader(); var loader = new THREE.FileLoader();
...@@ -728,14 +905,23 @@ THREE.GLTFLoader = ( function () { ...@@ -728,14 +905,23 @@ THREE.GLTFLoader = ( function () {
} ); } );
} );
}; };
GLTFParser.prototype.loadBuffers = function () { GLTFParser.prototype.loadBuffers = function () {
var json = this.json; var json = this.json;
var extensions = this.extensions;
var options = this.options; var options = this.options;
return _each( json.buffers, function ( buffer ) { return _each( json.buffers, function ( buffer, name ) {
if ( name === BINARY_EXTENSION_BUFFER_NAME ) {
return extensions[ EXTENSIONS.KHR_BINARY_GLTF ].body;
}
if ( buffer.type === 'arraybuffer' || buffer.type === undefined ) { if ( buffer.type === 'arraybuffer' || buffer.type === undefined ) {
...@@ -831,8 +1017,15 @@ THREE.GLTFLoader = ( function () { ...@@ -831,8 +1017,15 @@ THREE.GLTFLoader = ( 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( [
"bufferViews"
] ).then( function ( dependencies ) {
return _each( json.textures, function ( texture ) { return _each( json.textures, function ( texture ) {
if ( texture.source ) { if ( texture.source ) {
...@@ -840,8 +1033,15 @@ THREE.GLTFLoader = ( function () { ...@@ -840,8 +1033,15 @@ THREE.GLTFLoader = ( function () {
return new Promise( function ( resolve ) { return new Promise( function ( resolve ) {
var source = json.images[ texture.source ]; var source = json.images[ texture.source ];
var sourceUri = source.uri;
if (source.extensions && source.extensions[ EXTENSIONS.KHR_BINARY_GLTF ]) {
sourceUri = extensions[ EXTENSIONS.KHR_BINARY_GLTF ].loadTextureSourceUri( source, dependencies.bufferViews );
}
var textureLoader = THREE.Loader.Handlers.get( source.uri ); var textureLoader = THREE.Loader.Handlers.get( sourceUri );
if ( textureLoader === null ) { if ( textureLoader === null ) {
...@@ -851,7 +1051,7 @@ THREE.GLTFLoader = ( function () { ...@@ -851,7 +1051,7 @@ THREE.GLTFLoader = ( function () {
textureLoader.setCrossOrigin( options.crossOrigin ); textureLoader.setCrossOrigin( options.crossOrigin );
textureLoader.load( resolveURL( source.uri, options.path ), function ( _texture ) { textureLoader.load( resolveURL( sourceUri, options.path ), function ( _texture ) {
_texture.flipY = false; _texture.flipY = false;
...@@ -880,6 +1080,8 @@ THREE.GLTFLoader = ( function () { ...@@ -880,6 +1080,8 @@ THREE.GLTFLoader = ( function () {
} ); } );
} );
}; };
GLTFParser.prototype.loadMaterials = function () { GLTFParser.prototype.loadMaterials = function () {
...@@ -901,13 +1103,13 @@ THREE.GLTFLoader = ( function () { ...@@ -901,13 +1103,13 @@ THREE.GLTFLoader = ( function () {
var khr_material; var khr_material;
if ( material.extensions && material.extensions.KHR_materials_common ) { if ( material.extensions && material.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ] ) {
khr_material = material.extensions.KHR_materials_common; khr_material = material.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ];
} else if ( json.extensions && json.extensions.KHR_materials_common ) { } else if ( json.extensions && json.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ] ) {
khr_material = json.extensions.KHR_materials_common; khr_material = json.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ];
} }
...@@ -1599,6 +1801,7 @@ THREE.GLTFLoader = ( function () { ...@@ -1599,6 +1801,7 @@ THREE.GLTFLoader = ( function () {
GLTFParser.prototype.loadNodes = function () { GLTFParser.prototype.loadNodes = function () {
var json = this.json; var json = this.json;
var extensions = this.extensions;
var scope = this; var scope = this;
return _each( json.nodes, function ( node ) { return _each( json.nodes, function ( node ) {
...@@ -1657,8 +1860,7 @@ THREE.GLTFLoader = ( function () { ...@@ -1657,8 +1860,7 @@ THREE.GLTFLoader = ( function () {
"meshes", "meshes",
"skins", "skins",
"cameras", "cameras"
"extensions"
] ).then( function ( dependencies ) { ] ).then( function ( dependencies ) {
...@@ -1827,9 +2029,12 @@ THREE.GLTFLoader = ( function () { ...@@ -1827,9 +2029,12 @@ THREE.GLTFLoader = ( function () {
} }
if ( node.extensions && node.extensions.KHR_materials_common && node.extensions.KHR_materials_common.light ) { if ( node.extensions
&& node.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ]
&& node.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ].light ) {
var light = dependencies.extensions.KHR_materials_common.lights[ node.extensions.KHR_materials_common.light ]; var extensionLights = extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ].lights;
var light = extensionLights[ node.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ].light ];
_node.add( light ); _node.add( light );
...@@ -1845,70 +2050,6 @@ THREE.GLTFLoader = ( function () { ...@@ -1845,70 +2050,6 @@ THREE.GLTFLoader = ( function () {
}; };
GLTFParser.prototype.loadExtensions = function () {
var json = this.json;
return _each( json.extensions, function ( extension, extensionId ) {
switch ( extensionId ) {
case "KHR_materials_common":
var extensionNode = {
lights: {}
};
var lights = extension.lights;
for ( var lightId in lights ) {
var light = lights[ lightId ];
var lightNode;
var lightParams = light[ light.type ];
var color = new THREE.Color().fromArray( lightParams.color );
switch ( light.type ) {
case "directional":
lightNode = new THREE.DirectionalLight( color );
lightNode.position.set( 0, 0, 1 );
break;
case "point":
lightNode = new THREE.PointLight( color );
break;
case "spot":
lightNode = new THREE.SpotLight( color );
lightNode.position.set( 0, 0, 1 );
break;
case "ambient":
lightNode = new THREE.AmbientLight( color );
break;
}
if ( lightNode ) {
extensionNode.lights[ lightId ] = lightNode;
}
}
return extensionNode;
break;
}
} );
};
GLTFParser.prototype.loadScenes = function () { GLTFParser.prototype.loadScenes = function () {
var json = this.json; var json = this.json;
......
...@@ -79,7 +79,7 @@ ...@@ -79,7 +79,7 @@
top:72px; top:72px;
} }
#materials_extension_control { #extensions_control {
position:absolute; position:absolute;
top:104px; top:104px;
} }
...@@ -116,10 +116,14 @@ ...@@ -116,10 +116,14 @@
Animations Animations
<div class="controlValue"><input type="checkbox" checked onclick="toggleAnimations();">Play</input></div> <div class="controlValue"><input type="checkbox" checked onclick="toggleAnimations();">Play</input></div>
</div> </div>
<div class="control" id="materials_extension_control"> <div class="control" id="extensions_control">
Shaders Extension
<div class="controlValue"> <div class="controlValue">
<input type="checkbox" id="materials_extension_checkbox" checked onclick="toggleMaterialsExtension();">Use built-in</input> <select id="extensions_list" onchange="selectExtension();">
<option value="glTF">None</option>
<option value="glTF-MaterialsCommon">Built-in shaders</option>
<option value="glTF-Binary">Binary</option>
</select>
</div> </div>
</div> </div>
...@@ -238,10 +242,22 @@ ...@@ -238,10 +242,22 @@
var loadStartTime = Date.now(); var loadStartTime = Date.now();
var status = document.getElementById("status"); var status = document.getElementById("status");
status.innerHTML = "Loading..."; status.innerHTML = "Loading...";
for (var i = 0; i < extensionSelect.children.length; i++) {
var child = extensionSelect.children[i];
child.disabled = sceneInfo.extensions.indexOf(child.value) === -1;
if (child.disabled && child.selected) {
extensionSelect.value = extension = 'glTF';
}
}
var url = sceneInfo.url; var url = sceneInfo.url;
var r = eval("/" + '\%s' + "/g"); var r = eval("/" + '\%s' + "/g");
var dir = useMaterialsExtension ? 'glTF-MaterialsCommon' : 'glTF'; url = url.replace(r, extension);
url = url.replace(r, dir);
if (extension === 'glTF-Binary') {
url = url.replace('.gltf', '.glb');
}
var loadStartTime = Date.now(); var loadStartTime = Date.now();
var status = document.getElementById("status"); var status = document.getElementById("status");
...@@ -405,14 +421,16 @@ ...@@ -405,14 +421,16 @@
animationTime: 3, animationTime: 3,
addLights:true, addLights:true,
shadows:true, shadows:true,
addGround:true addGround:true,
extensions: ["glTF", "glTF-MaterialsCommon", "glTF-Binary"]
}, },
{ {
name : "Duck", url : "./models/gltf/duck/%s/duck.gltf", name : "Duck", url : "./models/gltf/duck/%s/duck.gltf",
cameraPos: new THREE.Vector3(0, 3, 5), cameraPos: new THREE.Vector3(0, 3, 5),
addLights:true, addLights:true,
addGround:true, addGround:true,
shadows:true shadows:true,
extensions: ["glTF", "glTF-MaterialsCommon", "glTF-Binary"]
}, },
{ {
name : "Cesium Man", url : "./models/gltf/CesiumMan/%s/Cesium_Man.gltf", name : "Cesium Man", url : "./models/gltf/CesiumMan/%s/Cesium_Man.gltf",
...@@ -420,7 +438,8 @@ ...@@ -420,7 +438,8 @@
objectRotation: new THREE.Euler(0, 0, 0), objectRotation: new THREE.Euler(0, 0, 0),
addLights:true, addLights:true,
addGround:true, addGround:true,
shadows:true shadows:true,
extensions: ["glTF", "glTF-MaterialsCommon", "glTF-Binary"]
}, },
{ {
name : "Cesium Milk Truck", name : "Cesium Milk Truck",
...@@ -428,7 +447,8 @@ ...@@ -428,7 +447,8 @@
cameraPos: new THREE.Vector3(0, 3, 10), cameraPos: new THREE.Vector3(0, 3, 10),
addLights:true, addLights:true,
addGround:true, addGround:true,
shadows:true shadows:true,
extensions: ["glTF", "glTF-MaterialsCommon", "glTF-Binary"]
}, },
{ {
name : "Snowflake", name : "Snowflake",
...@@ -438,7 +458,8 @@ ...@@ -438,7 +458,8 @@
objectPosition: new THREE.Vector3(0, 0, 0), objectPosition: new THREE.Vector3(0, 0, 0),
addLights:false, addLights:false,
addGround:false, addGround:false,
shadows:false shadows:false,
extensions: ["glTF"]
}, },
{ {
name : "Snowflakes", name : "Snowflakes",
...@@ -447,7 +468,8 @@ ...@@ -447,7 +468,8 @@
objectPosition: new THREE.Vector3(-1200, -1200, 0), objectPosition: new THREE.Vector3(-1200, -1200, 0),
addLights:false, addLights:false,
addGround:false, addGround:false,
shadows:false shadows:false,
extensions: ["glTF"]
} }
]; ];
...@@ -558,15 +580,14 @@ ...@@ -558,15 +580,14 @@
} }
var useextmaterials = document.getElementById("materials_extension_checkbox"); var extensionSelect = document.getElementById("extensions_list");
var useMaterialsExtension = useextmaterials.hasAttribute("checked"); var extension = extensionSelect.value;
function toggleMaterialsExtension() function selectExtension()
{ {
useMaterialsExtension = !useMaterialsExtension; extension = extensionSelect.value;
selectScene(); selectScene();
} }
function cleanup() { function cleanup() {
if (container && renderer) { if (container && renderer) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册