How to make material unique for GridMap?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By kubaxius

I have one MeshLib shared between multiple instances of GridMaps and I want to fade out one of them, without touching the rest. I tried doing this via changing alpha of the albedo of material, but it makes all GridMaps sharing the same material to change. I checked “Local to scene” on both material and MeshLib, but it still does not work - yes, MeshLibs are unique, but the material is still the same, one instance.

Is it a bug, or it is desirable behavior? And is there any possibility to do this without making separate files for the same material?

:bust_in_silhouette: Reply From: kubaxius

I still don’t really understand why this is happening, but I have created a function that makes materials unique:

func make_gridmap_materials_unique(gridmap: GridMap) -> Dictionary:
	var new_materials = {}
	for item in gridmap.get_meshes():
		if typeof(item) != TYPE_TRANSFORM:
			var i = 0
			while is_instance_valid(item.surface_get_material(i)):
				var id = RID(item.surface_get_material(i)).get_id()
				if not new_materials.has(id):
					new_materials[id] = item.surface_get_material(i).duplicate()
			
				item.surface_set_material(i, new_materials[id])
				i += 1
			
	return new_materials

#EDIT:
Ok, so this is definitely a bug. I created an Issue on Godot GitHub about this and came up with a better solution:

# first we have to make meshes unique, this is needed if you have different
# GridMaps sharing the same MeshLib
func make_meshes_unique():
	for id in mesh_library.get_item_list():
		mesh_library.set_item_mesh(id, mesh_library.get_item_mesh(id).duplicate())
#then we have to make materials unique for this MeshLibrary instance
func make_materials_unique():
	var materials = {}
	for id in mesh_library.get_item_list():
		var mesh = mesh_library.get_item_mesh(id)
		for i in mesh.get_surface_count():
			var res_name = mesh.surface_get_material(i).resource_name
			if not materials.has(res_name):
				materials[res_name] = mesh.surface_get_material(i).duplicate()
			mesh.surface_set_material(i, materials[res_name])