delete unused materials on a single object using python
Question:
After merging and separating objects, I have 69 materials on a single objects but only 50% of them are used by this object. How can I create a list of unused material per object?
I have tried the solution on the page (https://blender.stackexchange.com/questions/4817/how-to-know-which-object-is-using-a-material) but my problem is that materials are assigned to slots but slots are not used on any face of the mesh. I have to delete those.
Answers:
A list of materials used by the object can be generated by going through the mesh polygons.
used_mats = []
for f in obj.data.polygons:
used_mats.append(obj.material_slots[f.material_index].material)
If we use sets we can get a unique list and subtract used materials from listed materials.
import bpy
for obj in [o for o in bpy.data.objects if o.type=='MESH']:
mat_list = set(ms.material for ms in obj.material_slots)
used_mats = set(obj.material_slots[f.material_index].material
for f in obj.data.polygons)
unused_mats = mat_list - used_mats
print(obj.name, unused_mats)
for ms in obj.material_slots:
if ms.material in unused_mats:
ms.material = None
You may also want to go through and remove duplicates of the same material in different slots.
for obj in [o for o in bpy.data.objects if o.type=='MESH']:
for ms in obj.material_slots:
for cs in [s for s in obj.material_slots if s != ms]:
if cs.material == ms.material:
cs.material = None
While that just clears unused and duplicate slots, there is the step of removing any now unused slots. There is bpy.ops.object.material_slot_remove()
which will remove the last slot in the list, unless you find the instance of the UI item and adjust its properties.
This is a new op added in blender 2.9+
import bpy
for ob in bpy.context.selected_objects:
ob= bpy.context.active_object
bpy.ops.object.material_slot_remove_unused()
Then save the file and reopen
After merging and separating objects, I have 69 materials on a single objects but only 50% of them are used by this object. How can I create a list of unused material per object?
I have tried the solution on the page (https://blender.stackexchange.com/questions/4817/how-to-know-which-object-is-using-a-material) but my problem is that materials are assigned to slots but slots are not used on any face of the mesh. I have to delete those.
A list of materials used by the object can be generated by going through the mesh polygons.
used_mats = []
for f in obj.data.polygons:
used_mats.append(obj.material_slots[f.material_index].material)
If we use sets we can get a unique list and subtract used materials from listed materials.
import bpy
for obj in [o for o in bpy.data.objects if o.type=='MESH']:
mat_list = set(ms.material for ms in obj.material_slots)
used_mats = set(obj.material_slots[f.material_index].material
for f in obj.data.polygons)
unused_mats = mat_list - used_mats
print(obj.name, unused_mats)
for ms in obj.material_slots:
if ms.material in unused_mats:
ms.material = None
You may also want to go through and remove duplicates of the same material in different slots.
for obj in [o for o in bpy.data.objects if o.type=='MESH']:
for ms in obj.material_slots:
for cs in [s for s in obj.material_slots if s != ms]:
if cs.material == ms.material:
cs.material = None
While that just clears unused and duplicate slots, there is the step of removing any now unused slots. There is bpy.ops.object.material_slot_remove()
which will remove the last slot in the list, unless you find the instance of the UI item and adjust its properties.
This is a new op added in blender 2.9+
import bpy
for ob in bpy.context.selected_objects:
ob= bpy.context.active_object
bpy.ops.object.material_slot_remove_unused()
Then save the file and reopen