# Preventing duplication of materials and textures on a library of GLTF models

**URL:** <https://forum.babylonjs.com/t/preventing-duplication-of-materials-and-textures-on-a-library-of-gltf-models/52806>\
**Category:** Questions\
**Tags:** material, gltf, texture, gltffileloader, loaders\
**Created:** [August 14, 2024, 6:22pm UTC](https://forum.babylonjs.com/t/preventing-duplication-of-materials-and-textures-on-a-library-of-gltf-models/52806 "2024-08-14T18:22:19Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![HowdyLuda](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/howdyluda/32/32298_2.png) [@HowdyLuda](https://forum.babylonjs.com/u/HowdyLuda)\
**Post date:** [August 14, 2024, 6:22pm UTC](https://forum.babylonjs.com/t/preventing-duplication-of-materials-and-textures-on-a-library-of-gltf-models/52806/1 "2024-08-14T18:22:19Z")

</div>

We’re working on building a library of 3d assets, and wondering what the best strategy in Babylon is for re-using textures as much as possible.

Our 3D assets share a common set of textures. Let’s say there are around 100 textures in the game, and all of our GLTF models share them. Exporting from Blender and loading the GLTFs in the game results in each unique model loading a unique copy of the textures it uses, and I’m guessing that’s going to hurt performance and burden low-end devices as our scenes get more complex over time.

I’m thinking the best way to prevent this might be to turn off image export in Blender’s GLTF exporter, make sure Blender material names match a matching library created in Babylon, then apply the materials defined in Babylon to matching names on GLTF files after load? That seems like a huge pain, since it would require that artists maintain parity at all times.

Is there a more formal way of dealing with this?

---

<div class="post-metadata">

**Author:** ![Deltakosh](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/deltakosh/32/26635_2.png) [@Deltakosh](https://forum.babylonjs.com/u/Deltakosh)\
**Post date:** [August 14, 2024, 10:20pm UTC](https://forum.babylonjs.com/t/preventing-duplication-of-materials-and-textures-on-a-library-of-gltf-models/52806/2 "2024-08-14T22:20:26Z")

</div>

Good news is that by default the shaders will be shared (as well as textures if they come from the same url).

On your specific question your answer is the right one and I would encourage you to do it just because that way your glb files will be smaller. Perf wise as I mentioned earlier I’m not sure the gain will be huge

---

<div class="post-metadata">

**Author:** ![labris](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/labris/32/12576_2.png) [@labris](https://forum.babylonjs.com/u/labris)\
**Post date:** [August 15, 2024, 12:16am UTC](https://forum.babylonjs.com/t/preventing-duplication-of-materials-and-textures-on-a-library-of-gltf-models/52806/3 "2024-08-15T00:16:52Z")

</div>

Have a look at this thread - [The glTF optimization process and how to change the glTF image URI at runtime](https://forum.babylonjs.com/t/the-gltf-optimization-process-and-how-to-change-the-gltf-image-uri-at-runtime/41349)  
Still I think you need a set of materials, not a set of textures.

---

<div class="post-metadata">

**Author:** ![inteja](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/inteja/32/22553_2.png) [@inteja](https://forum.babylonjs.com/u/inteja)\
**Post date:** [August 15, 2024, 12:51am UTC](https://forum.babylonjs.com/t/preventing-duplication-of-materials-and-textures-on-a-library-of-gltf-models/52806/4 "2024-08-15T00:51:39Z")

</div>

The other advantage to having a dynamically loaded and assigned material/texture library, is that you can more easily target a range of devices and network bandwidths e.g. have “low”, “mid” and “high” resolution versions of your textures.

So my preference would be to not export any textures at all, not even placeholder textures, then just dynamically assign materials by mesh name after loading.

But yes, the process/workflow is more convoluted and less artist friendly.

Compartmentalising things like this can also help if you’re concerned about IP/assets being stolen. This won’t prevent it, but makes it more painful for people to have to reassemble.

---

<div class="post-metadata">

**Author:** ![kzhsw](https://avatars.discourse-cdn.com/v4/letter/k/848f3c/32.png) [@kzhsw](https://forum.babylonjs.com/u/kzhsw)\
**Post date:** [August 15, 2024, 1:53am UTC](https://forum.babylonjs.com/t/preventing-duplication-of-materials-and-textures-on-a-library-of-gltf-models/52806/5 "2024-08-15T01:53:39Z")

</div>

1. Load the 2 gltf with [glTF-Transform](https://github.com/donmccurdy/glTF-Transform)
2. [merge models](https://gltf-transform.dev/modules/functions/functions/mergeDocuments)
3. merge scenes

```js
        let scenes = doc.getRoot().listScenes();
        let defaultScene = scenes[0];
        doc.getRoot().setDefaultScene(defaultScene);
        // merge scene
        for (let j = 1; j < scenes.length; j++) {
            let children = scenes[j].listChildren();
            for (let k = 0; k < children.length; k++) {
                let node = children[k];
                scenes[j].removeChild(node);
                defaultScene.addChild(node);
            }
            scenes[j].dispose();
        }

```

1. [unpartition](https://gltf-transform.dev/modules/functions/functions/unpartition) and [dedup](https://gltf-transform.dev/modules/functions/functions/dedup)
2. Export it and load the merged glb

---

<div class="post-metadata">

**Author:** ![labris](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/labris/32/12576_2.png) [@labris](https://forum.babylonjs.com/u/labris)\
**Post date:** [August 15, 2024, 2:02am UTC](https://forum.babylonjs.com/t/preventing-duplication-of-materials-and-textures-on-a-library-of-gltf-models/52806/6 "2024-08-15T02:02:21Z")

</div>

What if there are several dozens of GLB and some of them should be moving?

> [@kzhsw](#):
>
> [unpartition](https://gltf-transform.dev/modules/functions/functions/unpartition) and [dedup](https://gltf-transform.dev/modules/functions/functions/dedup)

I believe [prune](https://gltf-transform.dev/modules/functions/functions/prune) would be also useful here.

---

<div class="post-metadata">

**Author:** ![kzhsw](https://avatars.discourse-cdn.com/v4/letter/k/848f3c/32.png) [@kzhsw](https://forum.babylonjs.com/u/kzhsw)\
**Post date:** [August 15, 2024, 2:04am UTC](https://forum.babylonjs.com/t/preventing-duplication-of-materials-and-textures-on-a-library-of-gltf-models/52806/7 "2024-08-15T02:04:41Z")

</div>

Yes, but [prune](https://gltf-transform.dev/modules/functions/functions/prune) seems kind of [aggressive](https://github.com/donmccurdy/glTF-Transform/pull/1270) in recent versions

---

<div class="post-metadata">

**Author:** ![shaderbytes](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/shaderbytes/32/174_2.png) [@shaderbytes](https://forum.babylonjs.com/u/shaderbytes)\
**Post date:** [August 15, 2024, 11:32am UTC](https://forum.babylonjs.com/t/preventing-duplication-of-materials-and-textures-on-a-library-of-gltf-models/52806/8 "2024-08-15T11:32:08Z")

</div>

> [@HowdyLuda](#):
>
> I’m thinking the best way to prevent this might be to turn off image export in Blender’s GLTF exporter, make sure Blender material names match a matching library created in Babylon, then apply the materials defined in Babylon to matching names on GLTF files after load? That seems like a huge pain, since it would require that artists maintain parity at all times.

Well there is another issue if you dont do this , regardless of babylon sharing textures in shaders… the other issue is that materials with the same name are not resolved to a single material by the engine.

eg , if you have 10 glb models , each of them having a material named “mat1” , if you load all these models into the scene , you will have 10 materials named mat1. This becomes a huge problem when you are doing dynamic color changes or texture replacements on a material. Since your changes would only affect one of the mat1 materials.

I have personally had to deal with this issue building configurators. I resorted to having to check all the materials on a loaded model vs what already exists in the scene. Then switch any matching marerials for the existing ones. This made sure all models with a same named material actually shared a same single material.

In regards to artists and a more complex workflow, this is the nature of the beast when wanting to actually build more professional software. I can assure you in any bigger studio involving asset pipelines , artists would have to follow conventions to make sure the assets are ready for pipeline processing, so this is kind of an expected aspect of a more complex system.

In regards to including textures , I have to agree with others here in saying after doing this for a while I found not including textures is the most flexible manner to do it. The process of mapping these and loading them can be made easier by automating some pipeline procedures with code.

I personally use custom python scripts to bake textures , save them and export glb models to specific folders , then build up a json file mapping textures to materials , even material types ( for custom shaders ) etc. Obviously my project is built to understand the pipelines output directories and the json files.

Once you have a system in place , the asset pipeline actually becomes easier and faster.

---

<div class="post-metadata">

**Author:** ![HowdyLuda](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/howdyluda/32/32298_2.png) [@HowdyLuda](https://forum.babylonjs.com/u/HowdyLuda)\
**Post date:** [August 15, 2024, 10:54pm UTC](https://forum.babylonjs.com/t/preventing-duplication-of-materials-and-textures-on-a-library-of-gltf-models/52806/9 "2024-08-15T22:54:30Z")

</div>

Thank you all!

@Deltakosh I’m trying to demonstrate locally that materials are shared when coming from the same URI.

In the following playground, I load the exact same GLTF three times, and I get three copies of the material. Is that expected behavior, or are you referring to creating mesh instances?

> **[Babylon.js Playground](https://playground.babylonjs.com/#WGZLGJ)**
>
> Babylon.js playground is a live editor for Babylon.js WebGL 3D scenes

---

<div class="post-metadata">

**Author:** ![Deltakosh](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/deltakosh/32/26635_2.png) [@Deltakosh](https://forum.babylonjs.com/u/Deltakosh)\
**Post date:** [August 16, 2024, 3:28pm UTC](https://forum.babylonjs.com/t/preventing-duplication-of-materials-and-textures-on-a-library-of-gltf-models/52806/10 "2024-08-16T15:28:36Z")

</div>

This does not seem to be the correct PG. I see it loaded only once

---

<div class="post-metadata">

**Author:** ![labris](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/labris/32/12576_2.png) [@labris](https://forum.babylonjs.com/u/labris)\
**Post date:** [August 16, 2024, 4:25pm UTC](https://forum.babylonjs.com/t/preventing-duplication-of-materials-and-textures-on-a-library-of-gltf-models/52806/11 "2024-08-16T16:25:54Z")

</div>

Here is small and very simple example of removing material duplicates by name after loading - [https://playground.babylonjs.com/#WGZLGJ#10502](https://playground.babylonjs.com/#WGZLGJ#10502)

 ![image](https://us1.discourse-cdn.com/flex024/uploads/babylonjs/original/3X/6/1/617d3659885aac98cd267182c09ed9870478cadd.jpeg)

---

<div class="post-metadata">

**Author:** ![Deltakosh](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/deltakosh/32/26635_2.png) [@Deltakosh](https://forum.babylonjs.com/u/Deltakosh)\
**Post date:** [August 16, 2024, 4:31pm UTC](https://forum.babylonjs.com/t/preventing-duplication-of-materials-and-textures-on-a-library-of-gltf-models/52806/12 "2024-08-16T16:31:49Z")

</div>

And as you can see (thanks @labris), the internal texture are the same even without replacing the materials:  
[glTF Loader Demo | Babylon.js Playground (babylonjs.com)](https://playground.babylonjs.com/#WGZLGJ#10503)

The texture object is just a shell around the real data which is shared

---

<div class="post-metadata">

**Author:** ![HowdyLuda](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/howdyluda/32/32298_2.png) [@HowdyLuda](https://forum.babylonjs.com/u/HowdyLuda)\
**Post date:** [August 16, 2024, 5:12pm UTC](https://forum.babylonjs.com/t/preventing-duplication-of-materials-and-textures-on-a-library-of-gltf-models/52806/13 "2024-08-16T17:12:27Z")

</div>

Sorry, forgot to save before copying the URL.

@deltakosh I thought you were saying that Babylon should automatically detect duplicate materials and textures with this statement “by default the shaders will be shared (as well as textures if they come from the same url).”

I just took the sandbox that @labris sent over and I see four copies of the BoomBox material in the inspector, and four copies of each texture:

> **[Babylon.js Playground](https://playground.babylonjs.com/#WGZLGJ%2310503)**
>
> Babylon.js playground is a live editor for Babylon.js WebGL 3D scenes

I thought that meant it would automatically detect the duplicates, but it looks like you have to do that manually.

Thanks all for your help.

---

<div class="post-metadata">

**Author:** ![labris](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/labris/32/12576_2.png) [@labris](https://forum.babylonjs.com/u/labris)\
**Post date:** [August 16, 2024, 5:27pm UTC](https://forum.babylonjs.com/t/preventing-duplication-of-materials-and-textures-on-a-library-of-gltf-models/52806/14 "2024-08-16T17:27:44Z")

</div>

In my PG there is only one material 🙂 - [https://playground.babylonjs.com/#WGZLGJ#10502](https://playground.babylonjs.com/#WGZLGJ#10502)

 ![image](https://us1.discourse-cdn.com/flex024/uploads/babylonjs/original/3X/2/8/28dbc795cb191fedc5a14d4693fcc7fc26f82ca6.png)

---

<div class="post-metadata">

**Author:** ![HowdyLuda](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/howdyluda/32/32298_2.png) [@HowdyLuda](https://forum.babylonjs.com/u/HowdyLuda)\
**Post date:** [August 16, 2024, 5:33pm UTC](https://forum.babylonjs.com/t/preventing-duplication-of-materials-and-textures-on-a-library-of-gltf-models/52806/15 "2024-08-16T17:33:58Z")

</div>

Interesting, maybe there’s a bug here? I’m using Chrome, MacOS 14.6.1

What I’m seeing:

 ![Screenshot 2024-08-16 at 10.32.02 AM](https://us1.discourse-cdn.com/flex024/uploads/babylonjs/original/3X/5/9/59a3e0d05b94de4e834af15f7c6f272d8d234b6f.jpeg)

Is there perhaps a Chrome setting I might have fiddled with that would result in this?  
Otherwise, we are looking at the exact same playground.

---

<div class="post-metadata">

**Author:** ![labris](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/labris/32/12576_2.png) [@labris](https://forum.babylonjs.com/u/labris)\
**Post date:** [August 16, 2024, 5:44pm UTC](https://forum.babylonjs.com/t/preventing-duplication-of-materials-and-textures-on-a-library-of-gltf-models/52806/16 "2024-08-16T17:44:29Z")

</div>

This is Deltakosh PG - [https://playground.babylonjs.com/#WGZLGJ#10503](https://playground.babylonjs.com/#WGZLGJ#10503)  
My PG has another URL - [https://playground.babylonjs.com/#WGZLGJ#10502](https://playground.babylonjs.com/#WGZLGJ#10502) 🙂  
The code is a bit different.

 ![image](https://us1.discourse-cdn.com/flex024/uploads/babylonjs/original/3X/3/7/37749937a7728e2575b2a1f57baeb3af0a8e211c.png)

---

<div class="post-metadata">

**Author:** ![HowdyLuda](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/howdyluda/32/32298_2.png) [@HowdyLuda](https://forum.babylonjs.com/u/HowdyLuda)\
**Post date:** [August 16, 2024, 5:47pm UTC](https://forum.babylonjs.com/t/preventing-duplication-of-materials-and-textures-on-a-library-of-gltf-models/52806/17 "2024-08-16T17:47:32Z")

</div>

OK, sorry. Sounds like it’s working as expected, then.

---

<div class="post-metadata">

**Author:** ![brightMoon](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/brightmoon/32/9959_2.png) [@brightMoon](https://forum.babylonjs.com/u/brightMoon)\
**Post date:** [August 17, 2024, 8:30am UTC](https://forum.babylonjs.com/t/preventing-duplication-of-materials-and-textures-on-a-library-of-gltf-models/52806/18 "2024-08-17T08:30:49Z")

</div>

Because its material has been dispose.

 ![image](https://us1.discourse-cdn.com/flex024/uploads/babylonjs/original/3X/e/2/e2a722f097befbc7b23bffa98c3646037e2776d8.png)

---

<div class="post-metadata">

**Author:** ![Keslinger](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/keslinger/32/9810_2.png) [@Keslinger](https://forum.babylonjs.com/u/Keslinger)\
**Post date:** [August 18, 2024, 4:12am UTC](https://forum.babylonjs.com/t/preventing-duplication-of-materials-and-textures-on-a-library-of-gltf-models/52806/19 "2024-08-18T04:12:41Z")

</div>

Seems like you have some solutions already, but in regards to a common texture directory (this is separate from the duplicate material question ):

I export .gltf (binary) instead of .glb and export the texture directory as a relative path (“../textures” ).

I made a tweak to the loader to allow relative paths during texture loading. Unfortunately, the validation method wasn’t public, so I had to tell Typescript to ignore my “hack”.

More discussion in an old thread here:

> [@Relative/absolute paths to texture images](https://forum.babylonjs.com/t/relative-absolute-paths-to-texture-images/38244/6):
>
> Thanks! Your comment pointed me in the direction of a hacky monkey patch that gets things working for me. I do think we could perhaps either improve the docs or add some support for this. This is my understanding: According to the glTF spec a .glb file can contain resources (texture images) - these can be either Base64 encoded URIs, or relative or absolute URLs to the resource file. For security/privacy reasons, BabylonJS only supports URIs below the rootUrl of the file being loaded. Absolu…

IIRC, the final code needed was significantly less complicated than was originally discussed. If you want to pursue this option and need a PG, I can probably throw something together.

---

<div class="post-metadata">

**Author:** ![HowdyLuda](https://sea2.discourse-cdn.com/flex024/user_avatar/forum.babylonjs.com/howdyluda/32/32298_2.png) [@HowdyLuda](https://forum.babylonjs.com/u/HowdyLuda)\
**Post date:** [August 23, 2024, 10:23pm UTC](https://forum.babylonjs.com/t/preventing-duplication-of-materials-and-textures-on-a-library-of-gltf-models/52806/20 "2024-08-23T22:23:40Z")

</div>

Thanks for that tip! I committed to GLB so long ago that it didn’t occur to me to look at the GLTF exporter options.
