Is your feature request related to a problem? Please describe.
Background:
I'm working on VRM materials, and I'm trying to utilize the GLTFLoader plugin system.
VRM uses not only the extension VRMC_materials_mtoon-1.0
(it's still a draft of new version though) but also uses KHR_materials_unlit
at the same time as a fallback, attached as material extensions.
However, the behavior of loading KHR_materials_unlit
is not built on the plugin system and hardcoded on the GLTFLoader itself, prioritizing its behavior than any other plugins registered.
I assume it's because it must delete properties that is related to pbr (metallic
and roughness
, for example) when it uses MeshBasicMaterial
to prevent emitting expected warnings (that says "hey, I don't know this parameter").
Describe the solution you'd like
I think I can resolve this by doing them:
KHR_materials_unlit
, replacing with proper plugin system.delete
at extendMaterialParams
.GLTFLoader.register
should be revised.push
es given plugins into pluginCallbacks
, it prioritizes preinstalled plugins rather than user-defined plugins, since _invokeOne
will execute plugins in the order of the array. Describe alternatives you've considered
However, I can implement the MToon import from glTF in other ways. I thought it's great to have as a GLTFLoader plugin though.
Here is the implementation without plugin system, a mere function receives a result of GLTFLoader.
Additional context
-
Get rid of hardcoded behavior of KHR_materials_unlit, replacing with proper plugin system.
We'd like to get all of the extensions implemented with the extension system, but just haven't ported some over yet. If you're able to make a PR for KHR_materials_unlit, please do!
Also, I think GLTFLoader.register should be revised.
Any ideas how this might work? One option would be for each plugin to assign a .order: number
property, with defaults taking priorities in the 1000-2000 range so that user-defined plugins can put themselves earlier, or later, if needed. The plugins could just be sorted before parsing begins.
Also, I think GLTFLoader.register should be revised.
Any ideas how this might work? One option would be for each plugin to assign a .order: number property, with defaults taking priorities in the 1000-2000 range so that user-defined plugins can put themselves earlier, or later, if needed. The plugins could just be sorted before parsing begins.
Another option would be unregister
built-in plugins and then register
them again. They will move to the tail of the array. We need to expose registered plugins and built-in plugin classes tho.
We'd like to get all of the extensions implemented with the extension system, but just haven't ported some over yet. If you're able to make a PR for KHR_materials_unlit, please do!
I'm gonna try this at first. Thanks!
Another option would be
unregister
built-in plugins and thenregister
them again.
That sounds hacky a bit, that you have to know how the plugin system work in behind.
Add an ability to remove builtin plugins by exposing them sounds not bad though.
I was imagined using unshift
instead of push
because it's natural to prioritize user defined plugins, since it's natural to say that GLTFLoader prioritizes plugins that is registered later.
Is there any builtin plugin combination that is order dependant so far?
Is there any builtin plugin combination that is order dependant so far?
Not yet, I think, except that we do depend on having the GLTFParser invoked last (after all extensions).
If we eventually have enough extensions that we don't want to include them all by default then we could do something like this:
import { GLTFLoader, KHRONOS_EXTENSIONS } from 'three/examples/jsm/loaders/GLTFLoader.js';
var loader = new GLTFLoader().register(KHRONOS_EXTENSIONS);
// ...
... but I don't think we're at that point yet, and it would be a breaking change if we were. I think I'd prefer the .order
or .priority
property for solving this particular problem, but I'm not opposed to having a clearExtensions
or unregister
type method either.
I was imagined using
unshift
instead ofpush
because it's natural to prioritize user defined plugins
Maybe this would make sense to me in most of cases. So how about switching from push to unshift so far (I assume it resolves @FMS-Cat case), and then we start to think of the option of .order/priority
if we actually get more fine priority control request?
BTW Don, my understanding is glTF spec doesn't mention the priority of the extensions and determining the priorities is user or loader responsibility. Is that true? I think I asked you it before, but I would like to clarify just in case.
I'm thinking it would be ideal if the priority is defined in glTF asset level. Loders won't need to be worried about the priorities. And even if the priorities are differ between assets the loader can handle them.
That's true, the glTF (core) specification does not say when one extension should be prioritized over another. That's hard to do in general; for example the client might want to drop advanced material extensions on low-end devices according to some knowledge of which are most expensive to render in that particular engine, rather than based on an order statically defined in the file.
In some cases extensions specify overrides and exclusions themselves — for example KHR_materials_clearcoat
prohibits being applied to the same material as KHR_materials_unlit
.
Having user-defined extensions take priority over default ones sounds good to me!
Thanks for the explanation.
That's hard to do in general; for example the client might want to drop advanced material extensions on low-end devices according to some knowledge of which are most expensive to render in that particular engine, rather than based on an order statically defined in the file.
Ah, that makes sense. Even if the asset is able to define the priorities or give the hints the loader may still need to provide a way to users to control the priorities (e.g. prioritization depending on platforms as you mentioned).
Having user-defined extensions take priority over default ones sounds good to me!
So let's go with prioritizing user-defined extensions for now, and discuss prioritizations API more detail if we get more concrete use cases which are not covered by this change.
@FMS-Cat To clarify just in case, will 1. moving the unlit extension handler to plugin system and 2. prioritizing user-defined plugins over built-in plugins resolve your case?
Yes I think so. I'll try this after I finish my lunch 😋
Yeah, current plugin system can say "You can take priority, extension-san" but can't say "Hey you can't do that, I'll take the priority".
Considering the case of unlit and clearcoat, we might want to have a system that can nullify other plugins from a plugin.
we might want to have a system that can nullify other plugins from a plugin.
Yeah, I have been thinking for a while about the API which can disable built-in plugins. Like in the scenario Don mentioned user might want to disable some built-in plugins for certain platforms.
Maybe adding .unregisterByName( name: string )
or replacing .unregister( callback: function )
with .unregister( name: string )
? These change can affect the loader inside or the plugin API because currently plugins' .name
properties are unknown until they are instantiated tho.
.unregisterByName( name: string )
/ .unregister( name: string )
sounds good.
Most helpful comment
@FMS-Cat To clarify just in case, will 1. moving the unlit extension handler to plugin system and 2. prioritizing user-defined plugins over built-in plugins resolve your case?