Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GLTFLoader plugin system, first round #19144

Merged
merged 8 commits into from
Jun 11, 2020
179 changes: 147 additions & 32 deletions examples/js/loaders/GLTFLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ THREE.GLTFLoader = ( function () {
this.dracoLoader = null;
this.ddsLoader = null;

this.pluginCallbacks = [];
this.register( function ( parser ) { return new GLTFMaterialsClearcoatExtension( parser ); } );

}

GLTFLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype ), {
Expand Down Expand Up @@ -112,10 +115,35 @@ THREE.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' ) {

Expand Down Expand Up @@ -157,6 +185,29 @@ THREE.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 ) {
Expand All @@ -170,10 +221,6 @@ THREE.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;
Expand All @@ -200,7 +247,7 @@ THREE.GLTFLoader = ( function () {

default:

if ( extensionsRequired.indexOf( extensionName ) >= 0 ) {
if ( extensionsRequired.indexOf( extensionName ) >= 0 && plugins[ extensionName ] === undefined ) {

console.warn( 'THREE.GLTFLoader: Unknown extension "' + extensionName + '".' );

Expand All @@ -212,15 +259,8 @@ THREE.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 );

}
Expand Down Expand Up @@ -421,19 +461,29 @@ THREE.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 THREE.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 = [];

Expand Down Expand Up @@ -1398,10 +1448,11 @@ THREE.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
Expand All @@ -1427,6 +1478,18 @@ THREE.GLTFLoader = ( function () {

}

GLTFParser.prototype.setExtensions = function ( extensions ) {

this.extensions = extensions;

};

GLTFParser.prototype.setPlugins = function ( plugins ) {

this.plugins = plugins;

};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't intend for users to call setPlugins or setExtensions, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I don't expect users to call them.


GLTFParser.prototype.parse = function ( onLoad, onError ) {

var parser = this;
Expand Down Expand Up @@ -1530,6 +1593,38 @@ THREE.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
Expand All @@ -1554,23 +1649,35 @@ THREE.GLTFLoader = ( function () {
break;

case 'mesh':
dependency = this.loadMesh( index );
dependency = this._invokeOne( function ( ext ) {

return ext.loadMesh && ext.loadMesh( index );

} );
break;

case 'accessor':
dependency = this.loadAccessor( index );
break;

case 'bufferView':
dependency = this.loadBufferView( index );
dependency = this._invokeOne( function ( ext ) {

return ext.loadBufferView && ext.loadBufferView( index );

} );
break;

case 'buffer':
dependency = this.loadBuffer( index );
break;

case 'material':
dependency = this.loadMaterial( index );
dependency = this._invokeOne( function ( ext ) {

return ext.loadMaterial && ext.loadMaterial( index );

} );
break;

case 'texture':
Expand Down Expand Up @@ -2108,6 +2215,12 @@ THREE.GLTFLoader = ( function () {

};

GLTFParser.prototype.getMaterialType = function ( materialIndex ) {

return THREE.MeshStandardMaterial;

};

/**
* Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#materials
* @param {number} materialIndex
Expand Down Expand Up @@ -2143,8 +2256,6 @@ THREE.GLTFLoader = ( function () {
// Specification:
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#metallic-roughness-material

materialType = THREE.MeshStandardMaterial;

var metallicRoughness = materialDef.pbrMetallicRoughness || {};

materialParams.color = new THREE.Color( 1.0, 1.0, 1.0 );
Expand Down Expand Up @@ -2175,6 +2286,18 @@ THREE.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 ) {
Expand Down Expand Up @@ -2242,14 +2365,6 @@ THREE.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;
Expand Down
Loading