Conversation
|
From my perspective we would want to keep existing extensions registered by default to aid in usability, the goal would be to make it easier to add support for new extensions without modifying three.js - but I am hoping that we will continue the current practice of adding extensions that are supported “by default” without the user having to opt-in. |
|
It’d be nice if I could clean up #14099. Three day weekend coming up so could be in the next couple of days. |
|
As an experiment I've decided to use this to try to implement MESHOPT_compression (draft extension spec: KhronosGroup/glTF#1702). To implement this extension, I need to:
I was able to successfully implement this like this: One issue that I am running into however is that I am able to add a function call after bufferView gets loaded by overriding |
|
Thanks for the comments and trial. And sorry, I didn't write clearly. Regarding Regarding |
|
@takahirox Thanks! I've added support for |
Agreed (although I'd like to remove MSFT_texture_dds at some point...).
Yes, for KHR_ extensions at least, others on a case-by-case basis.
Seems like more work for you if it's already incorporated in this PR? Maybe @takahirox should just submit it with extra indentation, and then you can fix that to claim the |
|
|
||
| return parser._onAfter( 'Node', node, json.nodes[ index ] ); | ||
|
|
||
| } ); |
There was a problem hiding this comment.
Just curious — is it possible to put all the hooks into onDependency? E.g...
case 'node':
dependency = this._onBefore( type, index )
.then(( def ) => this._on( type, index, def ))
.then(( result, def ) => this.load( type, index, def ))
.then(( result ) => this._onAfter( type, index, def, result ));
break;That would be simpler to maintain, but I don't know if it's compatible with all the cases we need.
We may also want to measure parsing time before/after here. I'm a little worried that adding a chain of promises for every accessor might create a lot of overhead.
There was a problem hiding this comment.
is it possible to put all the hooks into
onDependency
I haven't looked into the all asset types yet and perhaps we need a bit change in .loadXXX(), but probably it's possible. Maybe like this?
// .getDependency()
case 'XXX':
dependency = this._onBefore(XXX, index (or json.XXXs[index])).then(function (def) {
return parser._on(XXX, def).then(function (customXXX) {
return parser.loadXXX(index, def, customXXX);
}).then(function (result) {
return parser._onAfter(XXX, result, def);
});
});
break;
// .loadXXX()
/**
* @param {number} xxxIndex
* @param {GLTF.definition} xxxDef
* @param {Object|null} customXXX (optional)
* @return {Promise<Object>}
*/
GLTFParser.prototype.loadXXX = function (xxxIndex, xxxDef, customXXX) {
var pending;
if (customXXX) {
pending = Promise.resolve(customXXX);
} else {
pending = create core spec promise object from xxxDef (and xxxIndex);
}
pending.then(function (xxx) {
// setting up common properties here
// for example name, position/quaternion/scale/matrix, and so on for Node
return xxx;
} );
};We may also want to measure parsing time before/after here.
Yes, that's the plan. I first wanted to share the rough sketch API idea.
There was a problem hiding this comment.
In the above my comment, I thought to pass customXXX to loadXXX() to let it set up common properties (name and so on) for example the ones in loadMaterial() but coming to think that it can be a bit messy and some extension handlers may not want the common properties to be overridden because they set the properties something special.
So considering to call .loadXXX() only if ._onXXX() doesn't create an object. Pros: .loadXXX() doesn't need to change other than taking from index to def (and index), we can keep the code clean. And the parser don't override anything extension handler made. Cons: Extension handlers may have duplicated codes with the ones in the parser because they need to even set up the common properties by themselves.
Regarding assignExtrasToUserData() and addUnknownExtensionsToUserData(), we may move out from .loadXXX() and call in getDependency() instead if we don't want to expose them?
case 'XXX':
dependency = this._onBefore(XXX, index (or json.XXXs[index])).then(function (def) {
return parser._on(XXX, def).then(function (customXXX) {
return customXXX || parser.loadXXX(index, def);
}).then(function (result) {
assignExtrasToUserData(result, def);
if (def.extensions) addUnknownExtensionsToUserData(extensions, result, def);
return parser._onAfter(XXX, result, def);
});
});
break;There was a problem hiding this comment.
With the API above (onBeforeXXX, onXXX, and onAfterXXX for all asset types + Map, Geometry, and GLTF) I measured the loading response time (from .load() to onLoad) of some models in gltf extension example on my Windows Chrome. The numbers are average of five time trials. I haven't looked into the detail yet but Promise chain seems to have non-negligible response time impact. But I guess (and hope) main thread blocking time may not be so different? If so, I hope this impact can be acceptable.
(I'm not sure yet why the Monster glTF-Draco numbers between dev and plugin are close... Five time trial is not may enough? Or draco uncompression processing can be dominant?)
| dev [ms] | plugin [ms] | plugin / dev [%] | |
|---|---|---|---|
| Boombox glTF | 42.81 | 51.13 | +19% |
| Boombox glTF-dds | 205.70 | 225.52 | +10% |
| Monster glTF | 49.06 | 74.62 | +52% |
| Monster glTF-Draco | 167.96 | 164.90 | -2% |
|
I'm having a bit of trouble reviewing all of this at once. Maybe consider my comment above (since it'd be easier to answer that question with all of the extensions included). And if that's OK, do you mind introducing the new plugin API with just a single extension first? |
Sent PR #18484 |
|
Closing in favor of #19144 |
From: #11682
This PR adds extensibility to
GLTFLoader. It adds puglin API and rewrites the existing extension handlers. I'm not sure if the API and implementation are good yet. So opened as draft PR. Feedback is very welcome.Benefits
GLTFParserby separating extension handlers from coreGLTFParserGLTFParserAPI
Live Demo
https://raw.githack.com/takahirox/three.js/GLTFLoaderPluginSystem/examples/webgl_loader_gltf_extensions.html
Notes
GLTFLoader.jsand registered as default because (a.) most of them are popular extensions and I want users to avoid import separated plugin files and (b.) some of them, for example Draco extension, rely on some logics implemented inGLTFLoader.jsand I couldn't clearly separate.KHR_extensions inGLTFLoader.jsand adding separated plugin files for other extensions intoexamples/js(m)/loaders/gltfPlugins/or somewhere if needed?onXXX, I implemented onlyTexture,Material,GeometryandNodein this draft PR for now because I first wanted to show the API and how the existing handlers can be rewritten. I'm thinking to add others in this or other PRs later. RegardingonBeforeXXX, I had a comment and I'm not sure yet if we really need. So I implemented onlyGLTFso far because I only see the request that they need "before" hook point for entire gltf.