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

Add support for glTF binary extension.

上级 95c35211
......@@ -24,9 +24,12 @@ THREE.GLTFLoader = ( function () {
var path = this.path && ( typeof this.path === "string" ) ? this.path : THREE.Loader.prototype.extractUrlBase( url );
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 );
......@@ -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' );
var parser = new GLTFParser( json, {
var parser = new GLTFParser( json, extensions, {
path: path || this.path,
crossOrigin: this.crossOrigin
......@@ -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 ************/
/*********************************/
......@@ -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
// replace those in the shader code
function replaceTHREEShaderAttributes( shaderText, technique ) {
......@@ -614,9 +777,10 @@ THREE.GLTFLoader = ( function () {
/* GLTF PARSER */
function GLTFParser( json, options ) {
function GLTFParser( json, extensions, options ) {
this.json = json || {};
this.extensions = extensions || {};
this.options = options || {};
// loader object cache
......@@ -710,17 +874,32 @@ THREE.GLTFLoader = ( function () {
GLTFParser.prototype.loadShaders = function () {
var json = this.json;
var extensions = this.extensions;
var options = this.options;
return _each( json.shaders, function ( shader ) {
return this._withDependencies( [
"bufferViews"
] ).then( function ( dependencies ) {
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();
loader.setResponseType( 'text' );
loader.load( resolveURL( shader.uri, options.path ), function ( shaderText ) {
var loader = new THREE.FileLoader();
loader.setResponseType( 'text' );
loader.load( resolveURL( shader.uri, options.path ), function ( shaderText ) {
resolve( shaderText );
resolve( shaderText );
} );
} );
......@@ -733,9 +912,16 @@ THREE.GLTFLoader = ( function () {
GLTFParser.prototype.loadBuffers = function () {
var json = this.json;
var extensions = this.extensions;
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 ) {
......@@ -831,52 +1017,68 @@ THREE.GLTFLoader = ( function () {
GLTFParser.prototype.loadTextures = function () {
var json = this.json;
var extensions = this.extensions;
var options = this.options;
return _each( json.textures, function ( texture ) {
if ( texture.source ) {
return this._withDependencies( [
return new Promise( function ( resolve ) {
"bufferViews"
var source = json.images[ texture.source ];
] ).then( function ( dependencies ) {
var textureLoader = THREE.Loader.Handlers.get( source.uri );
return _each( json.textures, function ( texture ) {
if ( textureLoader === null ) {
if ( texture.source ) {
textureLoader = new THREE.TextureLoader();
return new Promise( function ( resolve ) {
}
var source = json.images[ texture.source ];
var sourceUri = source.uri;
textureLoader.setCrossOrigin( options.crossOrigin );
if (source.extensions && source.extensions[ EXTENSIONS.KHR_BINARY_GLTF ]) {
textureLoader.load( resolveURL( source.uri, options.path ), function ( _texture ) {
sourceUri = extensions[ EXTENSIONS.KHR_BINARY_GLTF ].loadTextureSourceUri( source, dependencies.bufferViews );
_texture.flipY = false;
}
if ( texture.sampler ) {
var textureLoader = THREE.Loader.Handlers.get( sourceUri );
var sampler = json.samplers[ texture.sampler ];
if ( textureLoader === null ) {
_texture.magFilter = WEBGL_FILTERS[ sampler.magFilter ];
_texture.minFilter = WEBGL_FILTERS[ sampler.minFilter ];
_texture.wrapS = WEBGL_WRAPPINGS[ sampler.wrapS ];
_texture.wrapT = WEBGL_WRAPPINGS[ sampler.wrapT ];
textureLoader = new THREE.TextureLoader();
}
resolve( _texture );
textureLoader.setCrossOrigin( options.crossOrigin );
textureLoader.load( resolveURL( sourceUri, options.path ), function ( _texture ) {
_texture.flipY = false;
if ( texture.sampler ) {
var sampler = json.samplers[ texture.sampler ];
_texture.magFilter = WEBGL_FILTERS[ sampler.magFilter ];
_texture.minFilter = WEBGL_FILTERS[ sampler.minFilter ];
_texture.wrapS = WEBGL_WRAPPINGS[ sampler.wrapS ];
_texture.wrapT = WEBGL_WRAPPINGS[ sampler.wrapT ];
}
resolve( _texture );
}, undefined, function () {
}, undefined, function () {
resolve();
resolve();
} );
} );
} );
}
}
} );
} );
......@@ -901,13 +1103,13 @@ THREE.GLTFLoader = ( function () {
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 ];
}
......@@ -1413,7 +1615,7 @@ THREE.GLTFLoader = ( function () {
case 'POSITION':
geometry.addAttribute( 'position', bufferAttribute );
break;
case 'COLOR_0':
case 'COLOR0':
case 'COLOR':
......@@ -1599,6 +1801,7 @@ THREE.GLTFLoader = ( function () {
GLTFParser.prototype.loadNodes = function () {
var json = this.json;
var extensions = this.extensions;
var scope = this;
return _each( json.nodes, function ( node ) {
......@@ -1657,8 +1860,7 @@ THREE.GLTFLoader = ( function () {
"meshes",
"skins",
"cameras",
"extensions"
"cameras"
] ).then( function ( dependencies ) {
......@@ -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 );
......@@ -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 () {
var json = this.json;
......
......@@ -79,7 +79,7 @@
top:72px;
}
#materials_extension_control {
#extensions_control {
position:absolute;
top:104px;
}
......@@ -116,10 +116,14 @@
Animations
<div class="controlValue"><input type="checkbox" checked onclick="toggleAnimations();">Play</input></div>
</div>
<div class="control" id="materials_extension_control">
Shaders
<div class="control" id="extensions_control">
Extension
<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>
......@@ -238,10 +242,22 @@
var loadStartTime = Date.now();
var status = document.getElementById("status");
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 r = eval("/" + '\%s' + "/g");
var dir = useMaterialsExtension ? 'glTF-MaterialsCommon' : 'glTF';
url = url.replace(r, dir);
url = url.replace(r, extension);
if (extension === 'glTF-Binary') {
url = url.replace('.gltf', '.glb');
}
var loadStartTime = Date.now();
var status = document.getElementById("status");
......@@ -405,14 +421,16 @@
animationTime: 3,
addLights:true,
shadows:true,
addGround:true
addGround:true,
extensions: ["glTF", "glTF-MaterialsCommon", "glTF-Binary"]
},
{
name : "Duck", url : "./models/gltf/duck/%s/duck.gltf",
cameraPos: new THREE.Vector3(0, 3, 5),
addLights:true,
addGround:true,
shadows:true
shadows:true,
extensions: ["glTF", "glTF-MaterialsCommon", "glTF-Binary"]
},
{
name : "Cesium Man", url : "./models/gltf/CesiumMan/%s/Cesium_Man.gltf",
......@@ -420,7 +438,8 @@
objectRotation: new THREE.Euler(0, 0, 0),
addLights:true,
addGround:true,
shadows:true
shadows:true,
extensions: ["glTF", "glTF-MaterialsCommon", "glTF-Binary"]
},
{
name : "Cesium Milk Truck",
......@@ -428,7 +447,8 @@
cameraPos: new THREE.Vector3(0, 3, 10),
addLights:true,
addGround:true,
shadows:true
shadows:true,
extensions: ["glTF", "glTF-MaterialsCommon", "glTF-Binary"]
},
{
name : "Snowflake",
......@@ -438,7 +458,8 @@
objectPosition: new THREE.Vector3(0, 0, 0),
addLights:false,
addGround:false,
shadows:false
shadows:false,
extensions: ["glTF"]
},
{
name : "Snowflakes",
......@@ -447,7 +468,8 @@
objectPosition: new THREE.Vector3(-1200, -1200, 0),
addLights:false,
addGround:false,
shadows:false
shadows:false,
extensions: ["glTF"]
}
];
......@@ -558,15 +580,14 @@
}
var useextmaterials = document.getElementById("materials_extension_checkbox");
var useMaterialsExtension = useextmaterials.hasAttribute("checked");
function toggleMaterialsExtension()
var extensionSelect = document.getElementById("extensions_list");
var extension = extensionSelect.value;
function selectExtension()
{
useMaterialsExtension = !useMaterialsExtension;
extension = extensionSelect.value;
selectScene();
}
function cleanup() {
if (container && renderer) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册