Hello. I have a scene where multiple GLTFs are dynamically loaded, each with various materials, some of which are shared between them. I initially tried removing only the duplicate textures, since I noticed that some GLTFs, even when using the same source for both emissive and albedo channels, create separate textures for each channel in Babylon.js. This approach seemed to work initially.
However, I later realized that some materials were also duplicated, so I tried applying the same approach to materials, but for some reason, it doesn’t work — the duplicate material isn’t removed as expected. Additionally, in some cases, the scene.ready trigger doesn’t seem to be invoked, causing the scene to hang in a loading state indefinitely.
Any suggestions would be greatly appreciated.
ps: I read about a potential approach where I could load one GLTF containing only the materials, and then load the other GLTFs without materials, assigning the materials afterward. Unfortunately, this doesn’t really apply in my case because I’m not sure exactly which materials will be used across the GLTFs being loaded. Out of a library of 100 materials, only about 10 might actually be used, so loading the entire library just for a subset would be inefficient.
You can check the console to see the logs.
Thank you again for your help!
I think you don’t need to check if the material is ready before to dispose, or if you want ot check if it is ready you need to put a mesh as param else the function return false all the way.
line 107
About your second issue related scene.ready I have no idea
I have tackled this recently. There are at least 4 options I can think of:
Intercept materials/textures on load
Assign ids via gltf extras property
Use material.name as id
Reference counting
The advantage of 1 is that you do not instantiate materials/textures. But, as shown below, you might need to override a private method which is gonna get ugly.
Below is an example for 1. See the link for other overridable methods.
var defaultMaterialSingleton = null;
// See https://github.com/BabylonJS/Babylon.js/blob/master/packages/dev/loaders/src/glTF/2.0/glTFLoader.ts#L2151
export default function override(BABYLON) {
const defaultCreateDefaultMaterial = BABYLON.GLTF2.GLTFLoader.prototype._createDefaultMaterial;
BABYLON.GLTF2.GLTFLoader.prototype._createDefaultMaterial = function(name, babylonDrawMode) {
if (typeof name === "string" && name.startsWith("__GLTFLoader._default")) {
if (defaultMaterialSingleton === null) {
this._babylonScene._blockEntityCollection = !!this._assetContainer;
defaultMaterialSingleton = new BABYLON.BackgroundMaterial("GLTFEmptyMaterial"); //#todo is this the cheapest material possible?
this._babylonScene._blockEntityCollection = false;
defaultMaterialSingleton.fillMode = babylonDrawMode;
defaultMaterialSingleton.freeze();
}
defaultMaterialSingleton._parentContainer = this._assetContainer;
return defaultMaterialSingleton;
}
return defaultCreateDefaultMaterial.call(this, name, babylonDrawMode);
};
}
For 2 beware that you cannot set extra properties on textures
For 3, well it is a name not an id. Ensure that nothing touches it.
For 4, I mean whether a texture is used by any material and whether a material is used by any mesh. Works as long as you do not preload (and don’t assign) materials/textures for later use.