マテリアル一覧スクリプト

シーン内のマテリアル一覧を表示して、使っているオブジェクトを選択する機能と、使っているオブジェクトが無いマテリアルを削除する機能。
シーン内のマテリアルを掃除したかったのじゃよ。


.blender/scripts/ui

適当なファイル名(z_my_material.pyなど)
で保存すると、3D Viewの左側のパネル(「T」キーでトグル)に▼Materialsというのが
追加される。

import bpy

###############################################################################
# operator
###############################################################################
class MaterialSelectObject(bpy.types.Operator):
    '''select objects of material owner'''
    bl_idname = "material.select_objects"
    bl_label = "Select material owner objects"
    bl_options = {'REGISTER', 'UNDO'}

    name = bpy.props.StringProperty(name="name", description="material name")

    def execute(self, context):
        scene=context.scene
        m=bpy.data.materials[self.properties.name]
        bpy.ops.object.select_all(action='DESELECT')
        first=True
        selected=[]
        for o in scene.objects:
            if o.type=='MESH':
                found=False
                for i, slot in enumerate(o.material_slots):
                    if slot.material==m:
                        o.selected=True
                        if first:
                            scene.objects.active=o
                            first=False
                        o.active_material_index=i
                        found=True
                        selected.append(o.name)
                        break
        print(selected)                
        return {'FINISHED'}


class MaterialDelete(bpy.types.Operator):
    '''delete a material'''
    bl_idname = "material.delete"
    bl_label = "Delete a material"
    bl_options = {'REGISTER', 'UNDO'}

    name = bpy.props.StringProperty(name="name", description="material name")

    def execute(self, context):
        scene=context.scene
        m=bpy.data.materials[self.properties.name]
        def hasOwner():
            for o in scene.objects:
                if o.type=='MESH':
                    for i, slot in enumerate(o.material_slots):
                        if slot.material==m:
                            o.selected=True
                            scene.objects.active=o
                            o.active_material_index=i
                            return True
                
        if m.users==0:
            bpy.data.materials.remove(m)
        else:
            if hasOwner():
                # skip
                pass
            else:
                print('orphan', m.name, m.users)
                m.user_clear()
                bpy.data.materials.remove(m)

        return {'FINISHED'}


operators=[
    MaterialSelectObject,
    MaterialDelete,
    ]


###############################################################################
# panel
###############################################################################
class View3DPanel(bpy.types.Panel):
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'


class OBJECT_PT_materials(View3DPanel):
    bl_context = "objectmode"
    bl_label = "Materials"
    bl_default_closed = True

    def draw(self, context):
        layout = self.layout

        ob = context.object

        col = layout.column(align=True)
        col.label(text="materials")
        for m in bpy.data.materials:
            row = col.row()
            row.operator("material.select_objects", text=m.name).name=m.name
            row.operator("material.delete", text='del').name=m.name


classes = [
    OBJECT_PT_materials,
]


###############################################################################
# register
###############################################################################
def register():
    register = bpy.types.register
    for op in operators:
        register(op)
    for cls in classes:
        register(cls)


def unregister():
    unregister = bpy.types.unregister
    for cls in classes:
        unregister(cls)
    for op in operators:
        unregister(op)


if __name__ == "__main__":
    register()