Extending the glTF Loader in Babylon.js
If you are reading this, you probably already know about glTF 2.0. However, do you know that there are a handful of glTF extensions that add to the core functionality of glTF 2.0? For example, the KHR_lights_punctual extension allows point, directional, and spot lights to be included with a glTF asset. More extensions will be coming from the 3D Formats Working Group of the Khronos Group as the ecosystem evolves. This article describes at a high level how the glTF 2.0 loader in Babylon.js manages these extensions.
The glTF 2.0 loader in Babylon.js is built to be extensible via loader extensions. Some loader extensions are built-in while others are provided by the user. Typically, a loader extension either supports a glTF 2.0 extension or modifies the behavior of the loader in some way.
- Extensible — users can easily add custom extensions to the loader to change the behavior of the loader
- Modular — users can easily remove the code for unneeded extensions to reduce complexity or to reduce code size
With these principles, the code is more readable and easier to maintain since the core loader only handles just the glTF 2.0 core functionality while each separated loader extension handles the functionality of each glTF 2.0 extension.
For context, here is what a glTF file looks like at a glance:
Each object in this tree can be extended using glTF extensions.
The glTF loader in Babylon.js traverses through this tree to load the asset. To handle extensions, the loader code has relevant extension points to enable modifications to the loading behavior. Extension code can then register itself to the loader to modify its behavior using these extension points.
Here is an example what the code looks like for the function that loads a scene:
The highlighted code is one of these extension points. The
loadSceneAsync function will return early if any of the registered extensions return a promise. The loader extensions also have access to the base loader so that they can invoke the default behaviors. Once a loader extension has been invoked, it will not be invoked again on the same object to prevent infinite recursion. Calling the default behavior will continue to load other extensions. This approach allows loader extensions to support many different scenarios without conflicting with each other.
All of the extension points are documented in the IGLTFLoaderExtension interface. See the classes in loaders/src/glTF/2.0/Extensions for all the extensions that are available by default. Note that some of them are experimental and are subject to change. More extension points will be added as the loader evolves.
Built-in extensions are great, but what if you want to do something custom for your scenario? The loader extension mechanism also allows you to create your own.
Here is a playground of a minimal example using the
loadMaterialPropertiesAsync extension point:
The highlighted code registers a new extension called
custom which replaces the default behavior of
loadMaterialPropertiesAsync with code that creates a standard material instead of a physical material.
Here is a real world example for loading VRM, a file format for handling 3D humanoid avatar data for VR applications based on glTF:
The Babylon.js Inspector also provides some basic debugging capabilities for the built-in glTF loader extensions.
For example, if you load up the sample model for
KHR_texture_transform and turn off the
KHR_texture_transform extension in the inspector, it will no longer use that extension.
This is often useful when debugging issues with extensions.
I’ve shown you a glimpse of the inner workings of the glTF 2.0 loader in Babylon.js, specifically how it manages glTF 2.0 extensions. I hope you find the loader extensions to be simple and easy to understand. I find it to be a good way to experiment to with new extensions. If you have any questions or want to add more extension points, ping me on the forum or twitter.
Gary Hsu — Babylon.js Team