0
$\begingroup$

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:

enter image description here

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

$\endgroup$
1
$\begingroup$

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):
    bpy.ops.object.material_slot_add()
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
$\endgroup$
0
$\begingroup$

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()
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.