|
@@ -12,6 +12,7 @@ import {
|
|
|
Box3,
|
|
|
BufferAttribute,
|
|
|
BufferGeometry,
|
|
|
+ CanvasTexture,
|
|
|
ClampToEdgeWrapping,
|
|
|
Color,
|
|
|
DirectionalLight,
|
|
@@ -19,6 +20,7 @@ import {
|
|
|
FileLoader,
|
|
|
FrontSide,
|
|
|
Group,
|
|
|
+ ImageBitmapLoader,
|
|
|
InterleavedBuffer,
|
|
|
InterleavedBufferAttribute,
|
|
|
Interpolant,
|
|
@@ -79,6 +81,9 @@ var GLTFLoader = ( function () {
|
|
|
this.dracoLoader = null;
|
|
|
this.ddsLoader = null;
|
|
|
|
|
|
+ this.pluginCallbacks = [];
|
|
|
+ this.register( function ( parser ) { return new GLTFMaterialsClearcoatExtension( parser ); } );
|
|
|
+
|
|
|
}
|
|
|
|
|
|
GLTFLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
|
|
@@ -175,10 +180,35 @@ var GLTFLoader = ( function () {
|
|
|
|
|
|
},
|
|
|
|
|
|
+ register: function ( callback ) {
|
|
|
+
|
|
|
+ if ( this.pluginCallbacks.indexOf( callback ) === -1 ) {
|
|
|
+
|
|
|
+ this.pluginCallbacks.push( callback );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return this;
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
+ unregister: function ( callback ) {
|
|
|
+
|
|
|
+ if ( this.pluginCallbacks.indexOf( callback ) !== -1 ) {
|
|
|
+
|
|
|
+ this.pluginCallbacks.splice( this.pluginCallbacks.indexOf( callback ), 1 );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return this;
|
|
|
+
|
|
|
+ },
|
|
|
+
|
|
|
parse: function ( data, path, onLoad, onError ) {
|
|
|
|
|
|
var content;
|
|
|
var extensions = {};
|
|
|
+ var plugins = {};
|
|
|
|
|
|
if ( typeof data === 'string' ) {
|
|
|
|
|
@@ -220,6 +250,29 @@ var GLTFLoader = ( function () {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ var parser = new GLTFParser( json, {
|
|
|
+
|
|
|
+ path: path || this.resourcePath || '',
|
|
|
+ crossOrigin: this.crossOrigin,
|
|
|
+ manager: this.manager
|
|
|
+
|
|
|
+ } );
|
|
|
+
|
|
|
+ parser.fileLoader.setRequestHeader( this.requestHeader );
|
|
|
+
|
|
|
+ for ( var i = 0; i < this.pluginCallbacks.length; i ++ ) {
|
|
|
+
|
|
|
+ var plugin = this.pluginCallbacks[ i ]( parser );
|
|
|
+ plugins[ plugin.name ] = plugin;
|
|
|
+
|
|
|
+ // Workaround to avoid determining as unknown extension
|
|
|
+ // in addUnknownExtensionsToUserData().
|
|
|
+ // Remove this workaround if we move all the existing
|
|
|
+ // extension handlers to plugin system
|
|
|
+ extensions[ plugin.name ] = true;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
if ( json.extensionsUsed ) {
|
|
|
|
|
|
for ( var i = 0; i < json.extensionsUsed.length; ++ i ) {
|
|
@@ -233,10 +286,6 @@ var GLTFLoader = ( function () {
|
|
|
extensions[ extensionName ] = new GLTFLightsExtension( json );
|
|
|
break;
|
|
|
|
|
|
- case EXTENSIONS.KHR_MATERIALS_CLEARCOAT:
|
|
|
- extensions[ extensionName ] = new GLTFMaterialsClearcoatExtension();
|
|
|
- break;
|
|
|
-
|
|
|
case EXTENSIONS.KHR_MATERIALS_UNLIT:
|
|
|
extensions[ extensionName ] = new GLTFMaterialsUnlitExtension();
|
|
|
break;
|
|
@@ -263,7 +312,7 @@ var GLTFLoader = ( function () {
|
|
|
|
|
|
default:
|
|
|
|
|
|
- if ( extensionsRequired.indexOf( extensionName ) >= 0 ) {
|
|
|
+ if ( extensionsRequired.indexOf( extensionName ) >= 0 && plugins[ extensionName ] === undefined ) {
|
|
|
|
|
|
console.warn( 'THREE.GLTFLoader: Unknown extension "' + extensionName + '".' );
|
|
|
|
|
@@ -275,15 +324,8 @@ var GLTFLoader = ( function () {
|
|
|
|
|
|
}
|
|
|
|
|
|
- var parser = new GLTFParser( json, extensions, {
|
|
|
-
|
|
|
- path: path || this.resourcePath || '',
|
|
|
- crossOrigin: this.crossOrigin,
|
|
|
- manager: this.manager
|
|
|
-
|
|
|
- } );
|
|
|
-
|
|
|
- parser.fileLoader.setRequestHeader( this.requestHeader );
|
|
|
+ parser.setExtensions( extensions );
|
|
|
+ parser.setPlugins( plugins );
|
|
|
parser.parse( onLoad, onError );
|
|
|
|
|
|
}
|
|
@@ -484,19 +526,29 @@ var GLTFLoader = ( function () {
|
|
|
*
|
|
|
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_clearcoat
|
|
|
*/
|
|
|
- function GLTFMaterialsClearcoatExtension() {
|
|
|
+ function GLTFMaterialsClearcoatExtension( parser ) {
|
|
|
|
|
|
+ this.parser = parser;
|
|
|
this.name = EXTENSIONS.KHR_MATERIALS_CLEARCOAT;
|
|
|
|
|
|
}
|
|
|
|
|
|
- GLTFMaterialsClearcoatExtension.prototype.getMaterialType = function () {
|
|
|
+ GLTFMaterialsClearcoatExtension.prototype.getMaterialType = function ( materialIndex ) {
|
|
|
|
|
|
return MeshPhysicalMaterial;
|
|
|
|
|
|
};
|
|
|
|
|
|
- GLTFMaterialsClearcoatExtension.prototype.extendParams = function ( materialParams, materialDef, parser ) {
|
|
|
+ GLTFMaterialsClearcoatExtension.prototype.extendMaterialParams = function ( materialIndex, materialParams ) {
|
|
|
+
|
|
|
+ var parser = this.parser;
|
|
|
+ var materialDef = parser.json.materials[ materialIndex ];
|
|
|
+
|
|
|
+ if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
|
|
|
+
|
|
|
+ return Promise.resolve();
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
var pending = [];
|
|
|
|
|
@@ -1461,10 +1513,11 @@ var GLTFLoader = ( function () {
|
|
|
|
|
|
/* GLTF PARSER */
|
|
|
|
|
|
- function GLTFParser( json, extensions, options ) {
|
|
|
+ function GLTFParser( json, options ) {
|
|
|
|
|
|
this.json = json || {};
|
|
|
- this.extensions = extensions || {};
|
|
|
+ this.extensions = {};
|
|
|
+ this.plugins = {};
|
|
|
this.options = options || {};
|
|
|
|
|
|
// loader object cache
|
|
@@ -1476,7 +1529,15 @@ var GLTFLoader = ( function () {
|
|
|
// BufferGeometry caching
|
|
|
this.primitiveCache = {};
|
|
|
|
|
|
- this.textureLoader = new TextureLoader( this.options.manager );
|
|
|
+ this.useImageBitmap = typeof createImageBitmap !== 'undefined';
|
|
|
+
|
|
|
+ // Use an ImageBitmapLoader if imageBitmaps are supported. Moves much of the
|
|
|
+ // expensive work of uploading a texture to the GPU off the main thread.
|
|
|
+ if ( this.useImageBitmap ) {
|
|
|
+ this.textureLoader = new ImageBitmapLoader( this.options.manager );
|
|
|
+ } else {
|
|
|
+ this.textureLoader = new TextureLoader( this.options.manager );
|
|
|
+ }
|
|
|
this.textureLoader.setCrossOrigin( this.options.crossOrigin );
|
|
|
|
|
|
this.fileLoader = new FileLoader( this.options.manager );
|
|
@@ -1490,6 +1551,18 @@ var GLTFLoader = ( function () {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ GLTFParser.prototype.setExtensions = function ( extensions ) {
|
|
|
+
|
|
|
+ this.extensions = extensions;
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ GLTFParser.prototype.setPlugins = function ( plugins ) {
|
|
|
+
|
|
|
+ this.plugins = plugins;
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
GLTFParser.prototype.parse = function ( onLoad, onError ) {
|
|
|
|
|
|
var parser = this;
|
|
@@ -1593,6 +1666,38 @@ var GLTFLoader = ( function () {
|
|
|
|
|
|
};
|
|
|
|
|
|
+ GLTFParser.prototype._invokeOne = function ( func ) {
|
|
|
+
|
|
|
+ var extensions = Object.values( this.plugins );
|
|
|
+ extensions.push( this );
|
|
|
+
|
|
|
+ for ( var i = 0; i < extensions.length; i ++ ) {
|
|
|
+
|
|
|
+ var result = func( extensions[ i ] );
|
|
|
+
|
|
|
+ if ( result ) return result;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ GLTFParser.prototype._invokeAll = function ( func ) {
|
|
|
+
|
|
|
+ var extensions = Object.values( this.plugins );
|
|
|
+ extensions.unshift( this );
|
|
|
+
|
|
|
+ var pending = [];
|
|
|
+
|
|
|
+ for ( var i = 0; i < extensions.length; i ++ ) {
|
|
|
+
|
|
|
+ pending.push( func( extensions[ i ] ) );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ return Promise.all( pending );
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
/**
|
|
|
* Requests the specified dependency asynchronously, with caching.
|
|
|
* @param {string} type
|
|
@@ -1617,7 +1722,11 @@ var GLTFLoader = ( function () {
|
|
|
break;
|
|
|
|
|
|
case 'mesh':
|
|
|
- dependency = this.loadMesh( index );
|
|
|
+ dependency = this._invokeOne( function ( ext ) {
|
|
|
+
|
|
|
+ return ext.loadMesh && ext.loadMesh( index );
|
|
|
+
|
|
|
+ } );
|
|
|
break;
|
|
|
|
|
|
case 'accessor':
|
|
@@ -1625,7 +1734,11 @@ var GLTFLoader = ( function () {
|
|
|
break;
|
|
|
|
|
|
case 'bufferView':
|
|
|
- dependency = this.loadBufferView( index );
|
|
|
+ dependency = this._invokeOne( function ( ext ) {
|
|
|
+
|
|
|
+ return ext.loadBufferView && ext.loadBufferView( index );
|
|
|
+
|
|
|
+ } );
|
|
|
break;
|
|
|
|
|
|
case 'buffer':
|
|
@@ -1633,7 +1746,11 @@ var GLTFLoader = ( function () {
|
|
|
break;
|
|
|
|
|
|
case 'material':
|
|
|
- dependency = this.loadMaterial( index );
|
|
|
+ dependency = this._invokeOne( function ( ext ) {
|
|
|
+
|
|
|
+ return ext.loadMaterial && ext.loadMaterial( index );
|
|
|
+
|
|
|
+ } );
|
|
|
break;
|
|
|
|
|
|
case 'texture':
|
|
@@ -1895,6 +2012,7 @@ var GLTFLoader = ( function () {
|
|
|
var parser = this;
|
|
|
var json = this.json;
|
|
|
var options = this.options;
|
|
|
+ var useImageBitmap = this.useImageBitmap;
|
|
|
var textureLoader = this.textureLoader;
|
|
|
|
|
|
var URL = self.URL || self.webkitURL;
|
|
@@ -1949,7 +2067,19 @@ var GLTFLoader = ( function () {
|
|
|
|
|
|
return new Promise( function ( resolve, reject ) {
|
|
|
|
|
|
- loader.load( resolveURL( sourceURI, options.path ), resolve, undefined, reject );
|
|
|
+ var onLoad = resolve;
|
|
|
+
|
|
|
+ if ( useImageBitmap ) {
|
|
|
+
|
|
|
+ onLoad = function ( imageBitmap ) {
|
|
|
+
|
|
|
+ resolve( new CanvasTexture( imageBitmap ) );
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ loader.load( resolveURL( sourceURI, options.path ), onLoad, undefined, reject );
|
|
|
|
|
|
} );
|
|
|
|
|
@@ -2171,6 +2301,12 @@ var GLTFLoader = ( function () {
|
|
|
|
|
|
};
|
|
|
|
|
|
+ GLTFParser.prototype.getMaterialType = function ( materialIndex ) {
|
|
|
+
|
|
|
+ return MeshStandardMaterial;
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
/**
|
|
|
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#materials
|
|
|
* @param {number} materialIndex
|
|
@@ -2206,8 +2342,6 @@ var GLTFLoader = ( function () {
|
|
|
// Specification:
|
|
|
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#metallic-roughness-material
|
|
|
|
|
|
- materialType = MeshStandardMaterial;
|
|
|
-
|
|
|
var metallicRoughness = materialDef.pbrMetallicRoughness || {};
|
|
|
|
|
|
materialParams.color = new Color( 1.0, 1.0, 1.0 );
|
|
@@ -2238,6 +2372,18 @@ var GLTFLoader = ( function () {
|
|
|
|
|
|
}
|
|
|
|
|
|
+ materialType = this._invokeOne( function ( ext ) {
|
|
|
+
|
|
|
+ return ext.getMaterialType && ext.getMaterialType( materialIndex );
|
|
|
+
|
|
|
+ } );
|
|
|
+
|
|
|
+ pending.push( this._invokeAll( function ( ext ) {
|
|
|
+
|
|
|
+ return ext.extendMaterialParams && ext.extendMaterialParams( materialIndex, materialParams );
|
|
|
+
|
|
|
+ } ) );
|
|
|
+
|
|
|
}
|
|
|
|
|
|
if ( materialDef.doubleSided === true ) {
|
|
@@ -2305,14 +2451,6 @@ var GLTFLoader = ( function () {
|
|
|
|
|
|
}
|
|
|
|
|
|
- if ( materialExtensions[ EXTENSIONS.KHR_MATERIALS_CLEARCOAT ] ) {
|
|
|
-
|
|
|
- var clearcoatExtension = extensions[ EXTENSIONS.KHR_MATERIALS_CLEARCOAT ];
|
|
|
- materialType = clearcoatExtension.getMaterialType();
|
|
|
- pending.push( clearcoatExtension.extendParams( materialParams, { extensions: materialExtensions }, parser ) );
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
return Promise.all( pending ).then( function () {
|
|
|
|
|
|
var material;
|