# Delete all materials that aren't assigned to a face?

Ok, I have several models that because various joining and un joining, have material slots that are there, but not assigned to any faces. Im exporting and would like these gone but there are too many to delete by hand:

Is there a script/way to get materials not assigned to a face to be eliminated?

Another method

• Gets all the face indices for each material in slots

How to get indices of the faces to which a material has been applied, using Python?

• If not assigned a slot, or slot is empty assign to material "None". Make sure there is no material named "None" in file

• If more than one slot has same material it merges them

• Will end up with a dictionary of materials by name to corresponding list of face indices, and those assigned to None.

• Note if a material index is found on a face that is outside the range of slots it is also assigned to "None".

• Make sure the slots list is the same length.

• Reassign slots and faces materials to dictionary values.

Test script. As pointed out by @Ratt always test on a copy, or don't save until happy with result. Simplifies material slot list of context object to those used, and an empty slot for outliers.

from collections import defaultdict
import bpy
context = bpy.context
ob = context.object

me = ob.data
slots = ob.material_slots
def getmname(idx):
if idx < len(slots):
name = slots[idx].name
name = name if name else "None"
else:
name = "None"
return name

matdic = defaultdict(list)

for f in me.polygons:
matdic[getmname(f.material_index)].append(f.index)

while len(slots) > len(matdic):
ob.active_material_index = 1
bpy.ops.object.material_slot_remove()

while len(slots) < len(matdic):
for i, (name, faces) in enumerate(matdic.items()):
slots[i].material = bpy.data.materials.get(name)
for f in faces:
me.polygons[f].material_index = i

• This works great, but it will only work on objects of type mesh, bearing in mind that there are also objects of type curves, this script will not perform on them, as there are actually no object.data.polygons (Sorry, but I was looking for a solution, which I can't find) – Noob Cat Oct 4 '20 at 14:45
• Imagine for a curve it would be a matter of looking at for index, s in enumerated(curve_object.data.splines) for the case of curves. – batFINGER Oct 6 '20 at 20:11

I would recommend testing this on a copy of your file first but based on my limited testing the following script should work for Blender 2.7x. Note this has to check every polygon of every mesh based on your description and may take some time. Script removes material slots which are not assigned to any polygons of a mesh. If a specific material is not assigned to any polygon of any mesh it will become orphan data and removed automatically on file save.

import bpy

objs = [obj for obj in bpy.data.objects if obj.type == 'MESH']

for obj in objs:
mats = obj.material_slots
used_slots = []
for poly in obj.data.polygons:
if poly.material_index not in used_slots:
used_slots.append(poly.material_index)
for i, mat in reversed(list(enumerate((mats)))):
if i not in used_slots:
obj.active_material_index = i
bpy.ops.object.material_slot_remove()