How to merge materials that use the same textures

Godot Version

4.4 /4.5

Question

hi, im looking for a way of merging materials that use the same texture - ive got multiple copies of the same texture and multiple folders with the same problem. I would like to store one version of each if possible. The scenes were all exported from Blender and the materials were using the same textures.

You can extract the materials of a model and use those extracted materials in the other models by pointing them to the same resource in the advanced import window. More info:

1 Like

(Google translator)
I think that if you export, from Blender, with the material included (gltf) then you will always see the duplicate textures.
I think the best thing is to create a resource → standardmaterial3D with your texture in the albedo and export the gltf, from Blender, without including the material.
Then, in Godot, you associate the material to your models through the surface material override.
Extracting the material, in this case (different models), I don’t know if it works since Godot usually gives the model name to the textures.

1 Like

Thanks, but the scenes have a lot of materials, is there a post import script for .glb files that checks material names and extracts them if they dont exist already, and uses the pre extracted one if they do? The script could use string matching to find substrings and ask the user if theyre the same, maybe it could show a preview.

I’m a complete novice.

Once you’ve specified that your materials are external, Godot remembers this, and even if you re-import the file, it will use the external materials.

I assume you’d only have to do this the first time for each material.

I don’t know if a post-import script would work for you, since the materials would be extracted during the import process and then your script would be executed.

However, you might want to look at the source code for the Godot importer itself for glb files to get an idea of ​​how to do what you want.

I’ve done it for a mesh library by looking at the code I found here that runs the editor (By clicking on the link you can see the complete code of the Godot editor):

1 Like

I was thinking it could be scripted with something like this post import script.

https://www.reddit.com/r/godot/comments/1azn4oj/ressource_import_script_to_apply_override/?rdt=54224

I can repeat the script here withou copyright issues:

@tool
extends EditorScenePostImport

var material = preload("res://Assets/Terrain/texture/BaseMaterial.tres")

func _post_import(scene):
	scene.get_children()[0].set_surface_override_material(0, material)
	return scene 

Obviously this doesnt extract the materials or search through the names comparing sub strings.

If you have several models, you will need to iterate on them.
Here you have better information and examples on this

Make one shared material with that texture and link it to all models.

So from what i understand of that script it first calls get_source_file() then creates a filename with .tres and then checks whether a mesh library exists with that name, if the file exists it removes everything, otherwise creates. It then calls a depth first search function iterating over the scene and adding MeshInstance3d objects to the mesh library. So the obvious modification would occur in the add_mesh() function with
meshLib.set_item_mesh(index, node.get_mesh())

Either there is a function meshLib.set_item_material() or set_surface_override_material() … that could work,
Or id have to use the node.get_mesh() and then get the material …
Then id have to write something like

var MaterialArray = []

func check_material(material, mesh_name)->Material:
    for mat in MaterialArray:
        if match_substring (get_albedo_texture_name(material), get_name(mat)):
            return mat
        else:
            var textures = []
            textures = get_all_textures(material)
            save_renamed_mat_textures(material, textures)
            MaterialArray.append(create_material( textures, material))
            return MaterialArray.get(MaterialArray.size()-1)

So i suppose the texture naming pattern is something like

[Glb filename] [texture name] [ number ]

I need to cut out the texture name for the matching substrings function

Then once something along those lines is working i’ve got to figure out what i can delete from the texture directory.
It seems essentially simple but its quite an intimidating volume of resources ive got to optimize … i need to create a backup. And the tool needs to be tested for bugs etc …

1 Like

I think you should create a backup in cloud storage. If it’s too large, upload it to multiple cloud apps. It might sound a headache but it’s easy with cx file manager as you can access multiple cloud apps within it.

1 Like

Yeah a cloud backup is an option, but ive got a couple of external drives that i can use so ill probably just work with local backups for now. The total used memory is only about 6GB and a lot of that is textures.

I’m currently developing shader materials, it would be good if i could directly import shaders from blender, but i have a protoype shader material that i can use to try to implement the blender shader.

I need to discover or create a material library resource type in Godot that i can read/write from in the script.