I am importing two GLB files in my scene, which are almost the same.. (two Vans with different lengths), and now all materials are Doubled.. that may not be a big deal, however when i try to change the color of a material…only the first one will change…
Read some similar topics.. with the idea to skip importing when its double.. but has this ever been implemented?
Welcome to the forums!
This should be possible. You need to decide how you want the materials to detected as a duplicate. Maybe the name of the material is enough. Then, you can create a loader extension that checks the materials by name and caches them so that if they have the same name, it will reuse the same material. Something like that should work. I can help you set this up in a playground if you can provide the assets.
@Hans75 There’s some code here from @shaderbytes to deduplicate materials that I’ve found useful.
I am quite surprised this is an issue.. Quite new to babylon, before have used a lot of threejs.. so maybe i am making the wrong assumptions.. even with double materials it shouldnt be an issue to address a specific one.. i have two objects A and B, but with the identical material ‘paint’..
var paint=scene.getMaterialByName(‘paint’) will get me one of them.. (probably the first one in object A)
var A = scene.getMeshByName(‘A’) will get me mesh of the first object… and
var B = scene.getMeshByName(‘B’) will get me the the second mesh..
If i want to change the paint in object B… i would expect this to work… but i get an error
var paintB = B.getMaterialByName(‘paint’) how is this supposed to work? or is MaterialByName only working for ‘scene’?
I used an existing playground, loading a GLB… as you can see in inspector.. materials are loaded double… how do i change the haircolor of the second girl..?
In your playground you are creating multiple materials sharing same name.
If you want both meshes to have same material, just dispose the double material and assign existing material instead. If you want them to have different materials rename the new material. Babylon.js Playground
Also to access mesh material you shouldn’t use getMaterialByName (it’s used for searching materials in the scene) For mesh it is just mesh.material
Hi!
I assume, you mean something like this:
class DedupMaterials implements IGLTFLoaderExtension {
public createMaterial(context: string, material: IMaterial, babylonDrawMode: number): Nullable<Material> {
let babylonMaterial = this._loader.babylonScene.getMaterialByName(material.name);
if (!babylonMaterial) babylonMaterial = this._loader.createMaterial(context, material, babylonDrawMode)
return babylonMaterial;
}
}
Altough the extensions have other undocumented hook: _loadMaterialAsync
Define this method to modify the default behavior when loading materials. Load material creates the material and then loads material properties
Maybe it is a better candidate for caching and avoiding redundant work?
Also,
the this._loader.createMaterial seems to call this._extensionsCreateMaterial and in turn extension.createMaterial recursively. How does it work?
That’s a good start. Normally to override a material, we should override both createMaterial and loadMaterialPropertiesAsync. In this case, we need to somehow indicate that this is a duplicate material, return the existing material, and don’t load the properties again. If the material is actually different, it will ignore them. The “User Extensions” section of this blog post has an example.
This is hidden because it’s not clear what the contract should be. You can use it, but the signature may change in the future.
The code internally tracks whether a loader extension has been called already and won’t call it again for the same glTF object.
Thanks for nice article and explanations!
So, my hypothesis is that overriding _loadMaterialAsync is kinda superior to createMaterial and loadMaterialProperties, and there’s no need to mark materials, they just won’t be called.
Is that corect?
I don’t know if it’s superior, but yes, overriding this will not set the material anymore. You will still need to manually assign the material though.