MRが楽しい

MRやVRについて学習したことを書き残す

Blender2.8で利用可能なpythonスクリプトを作る その68(マテリアルスロットのソートと重複削除)

本日は Blender の技術調査枠です。
Blender2.8で利用可能なpythonスクリプトを作ります。

マテリアルスロットを名前順でソートする

オブジェクトのマテリアルスロットの順序を名前でソートします。
・Script_sort_materialslot.py

# bpyインポート
import bpy

# 指定オブジェクトのマテリアルスロットをソートする
def sort_materialslot_name(arg_object:bpy.types.Object) -> bool:
    """指定オブジェクトのマテリアルスロットをソートする

    Args:
        arg_object (bpy.types.Object): 指定オブジェクト

    Returns:
        bool: 実行正否
    """

    # オブジェクトがメッシュであるか確認する
    if arg_object.type != 'MESH':
        # 指定オブジェクトがメッシュでない場合は処理しない
        return None

    # 比較継続フラグ
    change_flg = True

    # 並び替えが完了するまでループ
    while change_flg:
        # 比較継続フラグを初期化する
        change_flg = False

        # マテリアルスロットを走査する
        for num in range(len(arg_object.material_slots)-1):
            # マテリアルを取得する
            check_mat = arg_object.material_slots[num].material
            comp_mat = arg_object.material_slots[num+1].material

            # マテリアル名を比較する
            if check_mat.name > comp_mat.name:
                # 位置を入れ替える
                arg_object.active_material_index = num
                bpy.ops.object.material_slot_move(direction='DOWN')

                # 比較を継続する
                change_flg = True

    return True


# 関数の実行例
target_obj = bpy.data.objects.get("Cube")
sort_materialslot_name(target_obj)

・実行前
f:id:bluebirdofoz:20201018203829j:plain
・実行後
f:id:bluebirdofoz:20201018203838j:plain

マテリアルスロットの重複を削除する

オブジェクトに同じマテリアルを参照するマテリアルスロットがあれば削除します。
マテリアルスロットは削除すると、直上のマテリアルに割り当てが統合されるので、隣り合ったマテリアルにのみ重複チェックを実施しています。
前述のマテリアルスロットのソートと組み合わせて利用すると、全ての重複が削除されます。
・Script_delate_materialslot.py

# bpyインポート
import bpy

# マテリアルスロットの隣り合った重複を削除する
def delate_materialslot_duplicate(arg_object:bpy.types.Object) -> bool:
    """指定オブジェクトのマテリアルスロットをソートする

    Args:
        arg_object (bpy.types.Object): 指定オブジェクト

    Returns:
        bool: 実行正否
    """

    # オブジェクトがメッシュであるか確認する
    if arg_object.type != 'MESH':
        # 指定オブジェクトがメッシュでない場合は処理しない
        return None

    # 重複しているマテリアルスロットを削除する
    # 削除処理を行うので逆順に要素を追う
    for num in range(len(arg_object.material_slots)-1)[::-1]:
        # マテリアルを取得する
        check_mat = arg_object.material_slots[num].material
        comp_mat = arg_object.material_slots[num+1].material

        # マテリアル名を比較する
        if check_mat.name == comp_mat.name:
            # マテリアル名が同じならば削除する
            arg_object.active_material_index = num + 1
            bpy.ops.object.material_slot_remove()

    return True


# 関数の実行例
target_obj = bpy.data.objects.get("Cube")
delate_materialslot_duplicate(target_obj)

・実行前
f:id:bluebirdofoz:20201018203848j:plain
・実行後
f:id:bluebirdofoz:20201018203858j:plain

空マテリアルの削除

指定のオブジェクトからマテリアルが設定されていないからマテリアルを削除します。
・Script_delate_materialslot_empty

# bpyインポート
import bpy

# 空のマテリアルスロットを削除する
def delate_materialslot_empty(arg_object:bpy.types.Object) -> bool:
    """空のマテリアルスロットを削除する

    Args:
        arg_object (bpy.types.Object): 指定オブジェクト

    Returns:
        bool: 実行正否
    """

    # オブジェクトがメッシュであるか確認する
    if arg_object.type != 'MESH':
        # 指定オブジェクトがメッシュでない場合は処理しない
        return None

    # 重複しているマテリアルスロットを削除する
    # 削除処理を行うので逆順に要素を追う
    for num in range(len(arg_object.material_slots)-1)[::-1]:
        # マテリアルを取得する
        targetmat = arg_object.material_slots[num].material

        # マテリアルが空であるか
        if targetmat == None:
            # マテリアル名が同じならば削除する
            arg_object.active_material_index = num
            bpy.ops.object.material_slot_remove()

    return True


# 関数の実行例
target_obj = bpy.data.objects.get("Cube")
delate_materialslot_empty(target_obj)

・実行前
f:id:bluebirdofoz:20201021213302j:plain
・実行後
f:id:bluebirdofoz:20201021213321j:plain