MRが楽しい

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

Blender2.8でモンスター型のキャラクターモデルを作成する その1(仕上げ処理を自動化する)

本日はモンスター型モデルの作成枠です。
Blender2.8 環境での仕上げ処理をスクリプトで自動化します。
f:id:bluebirdofoz:20200405231517j:plain

以前、Blender2.79 で作成したモンスター型のキャラクターモデルを Blender2.8 環境に移行しました。
bluebirdofoz.hatenablog.com

今回は1万ポリゴン未満のローポリゴンモデルと、2万ポリゴン以上のハイポリゴンモデルを作成することを目的とします。
まずはその下準備として、ローポリゴンモデルとハイポリゴンモデルの出力処理をそれぞれ自動化したスクリプトを作成しました。
・Joint_HoloMon.py

# bpyインポート(Blender操作のため)
import bpy


# メイン関数
def main():
    # ハイポリゴンモデル作成とローポリゴンモデル作成を切り替える
    isHighModel = True

    # サブディビジョンサーフェスを適用するメッシュ
    sub_meshs = get_endswithmesh_namelist(arg_endswithname="_HP")

    # ローポリゴンモデルで削除するメッシュ
    lowdel_meshs = get_endswithmesh_namelist(arg_endswithname="_LD")

    # 結合オブジェクト名
    jointobj_name = 'JointModel'

    # ハイポリゴンモデル作成の場合の処理を実行する
    if isHighModel == True:
        # 指定のオブジェクトにサブディビジョンサーフェスを追加する
        for sub_mesh in sub_meshs:
            add_modifier_subdivision(arg_objectname=sub_mesh)

    # ローポリゴンモデル作成の場合の処理を実行する
    if isHighModel == False:
        # ハイポリゴンモデルでのみ利用するメッシュを削除する
        for lowdel_mesh in lowdel_meshs:
            delete_object_target(arg_objectname=lowdel_mesh)


    # 結合する全メッシュオブジェクトのオブジェクト名リストを取得する
    joint_meshs = get_mesh_namelist()

    # 各オブジェクトにモディファイアを適用する
    for joint_mesh in joint_meshs:
        apply_modifier_target(arg_objectname=joint_mesh)

    # オブジェクトを全て結合する
    join_objects_mesh(arg_targetnamelist=joint_meshs, arg_jointname=jointobj_name)

    return


# 全メッシュオブジェクト名のリストを作成する
def get_mesh_namelist():
    """全メッシュオブジェクト名のリストを作成する
    """
    # 空リストを作成
    mesh_names=[]
    # シーン中の全てのオブジェクトを走査する
    for obj in bpy.context.view_layer.objects:
        # オブジェクトがメッシュであるか確認する
        if obj.type == 'MESH':
            # 名称をリストに追加する
            mesh_names.append(obj.name)

    return mesh_names


# 指定の後方文字列のメッシュオブジェクト名のリストを作成する
def get_endswithmesh_namelist(arg_endswithname=""):
    """全メッシュオブジェクト名のリストを作成する
    
    Keyword Arguments:
        arg_endswithname {str} -- 先頭一致文字列 (default: {""})
    """

    # 空リストを作成
    mesh_names=[]
    # シーン中の全てのオブジェクトを走査する
    for obj in bpy.context.view_layer.objects:
        # オブジェクトがメッシュであるか確認する
        if obj.type == 'MESH':
            # オブジェクト名の先頭文字列が一致するか確認する
            if obj.name.endswith(arg_endswithname):
                # 名称をリストに追加する
                mesh_names.append(obj.name)

    return mesh_names


# 「サブディビジョンサーフェス」モディファイアの追加
# モディファイア追加の種類とマニュアル
# (https://docs.blender.org/api/current/bpy.ops.object.html#bpy.ops.object.gpencil_modifier_add)
def add_modifier_subdivision(arg_objectname="Default"):
    """「サブディビジョンサーフェス」モディファイアの追加
    
    Keyword Arguments:
        arg_objectname {str} -- 対象オブジェクト名 (default: {"Default"})
    """

    # 指定オブジェクトを取得する
    # (get関数は対象が存在しない場合 None が返る)
    targetob = bpy.data.objects.get(arg_objectname)

    # 指定オブジェクトが存在するか確認する
    if targetob == None:
        # 指定オブジェクトが存在しない場合は処理しない
        return

    # 変更オブジェクトをアクティブに変更する
    bpy.context.view_layer.objects.active = targetob

    # 「サブディビジョンサーフェス」モディファイアを追加する
    bpy.ops.object.modifier_add(type='SUBSURF')
    # 作成モディファイアを取得する
    selectmod = targetob.modifiers['Subdivision']
    # 細分化レベルを「1」に設定する
    selectmod.levels = 1

    return


# 指定オブジェクトの削除
def delete_object_target(arg_objectname=""):
    """指定オブジェクトの削除
    
    Keyword Arguments:
        arg_objectname {str} -- 削除するオブジェクト名 (default: {""})
    """

    # 指定オブジェクトを取得する
    # (get関数は対象が存在しない場合 None が返る)
    targetob = bpy.data.objects.get(arg_objectname)

    # 指定オブジェクトが存在するか確認する
    if targetob != None:
        # オブジェクトが存在する場合は削除を行う
        bpy.data.objects.remove(targetob)
    
    return


# 以下のモディファイアを適用する
# - ミラーモディファイア
# - シュリンクラップモディファイア
# - 細分割曲面モディファイア
# - 辺分離モディファイア
# - 厚み付けモディファイア
# - ベベルモディファイア
#     対象モディファイアを保持しない場合は無視する
def apply_modifier_target(arg_objectname=""):
    """特定のモディファイアを適用する
    
    Keyword Arguments:
        arg_objectname {str} -- 対象オブジェクト名 (default: {"Default"})
    """

    # 指定オブジェクトを取得する
    # (get関数は対象が存在しない場合 None が返る)
    targetob = bpy.data.objects.get(arg_objectname)

    # 指定オブジェクトが存在するか確認する
    if targetob == None:
        # 指定オブジェクトが存在しない場合は処理しない
        return

    # 変更オブジェクトをアクティブに変更する
    bpy.context.view_layer.objects.active = targetob

    # オブジェクトの全てモディファイアを走査する
    # モディファイアのタイプ一覧
    # (https://docs.blender.org/api/blender_python_api_2_71_release/bpy.types.Modifier.html)
    for modifier in targetob.modifiers:
        # ミラーモディファイアを適用する
        if modifier.type == 'MIRROR':
            bpy.ops.object.modifier_apply(apply_as='DATA',modifier=modifier.name)
        # 細分割曲面モディファイアを適用する
        if modifier.type == 'SUBSURF':
            bpy.ops.object.modifier_apply(apply_as='DATA',modifier=modifier.name)
        # シュリンクラップモディファイアを適用する
        if modifier.type == 'SHRINKWRAP':
            bpy.ops.object.modifier_apply(apply_as='DATA',modifier=modifier.name)
        # 辺分離モディファイアを適用する
        if modifier.type == 'EDGE_SPLIT':
            bpy.ops.object.modifier_apply(apply_as='DATA',modifier=modifier.name)
        # 厚み付けモディファイアを適用する
        if modifier.type == 'SOLIDIFY':
            bpy.ops.object.modifier_apply(apply_as='DATA',modifier=modifier.name)
        # ベベルモディファイアを適用する
        if modifier.type == 'BEVEL':
            bpy.ops.object.modifier_apply(apply_as='DATA',modifier=modifier.name)
    return


# メッシュオブジェクトの結合
def join_objects_mesh(arg_targetnamelist=[], arg_jointname=''):
    """メッシュオブジェクトを結合する
    
    Keyword Arguments:
        arg_objectname {list} -- 対象オブジェクト名リスト (default: {[]})
        arg_objectname {str} -- 結合オブジェクト名 (default: {""})
    """

    # 対象の全てのオブジェクトを走査する
    for targetname in arg_targetnamelist:
        # 指定オブジェクトを取得する
        # (get関数は対象が存在しない場合 None が返る)
        targetob = bpy.data.objects.get(targetname)

        # 指定オブジェクトが存在するか確認する
        if targetob == None:
            # 指定オブジェクトが存在しない場合は処理しない
            return

        # オブジェクトがメッシュであるか確認する
        if targetob.type == 'MESH':
            # メッシュであれば選択状態にする
            targetob.select_set(True)
            # 対象アクティブオブジェクトに切り替える
            # メッシュはアクティブオブジェクトに結合される
            bpy.context.view_layer.objects.active = targetob
        else:
            # メッシュでなければ選択状態にしない
            targetob.select_set(False)

    # オブジェクトの結合を実行する
    bpy.ops.object.join()

    # 結合オブジェクト名が設定されているか
    if len(arg_jointname):
        # オブジェクト名が設定されていれば名前を変更する
        bpy.context.view_layer.objects.active.name = arg_jointname

    return


# main関数の呼び出し
main()

こちらのスクリプトでは isHighModel 変数の True/False 値を切り替えることで、最後の仕上げ処理を切り替えています。
isHighModel を True にした場合、オブジェクト名の末尾に "_HP" と付くオブジェクトは細分割を行った上で結合を行います。
f:id:bluebirdofoz:20200405231700j:plain

isHighModel を False にした場合、細分割は行わず、オブクト名の末尾に "_LD" と付くオブジェクトを削除した上で結合を行います。
f:id:bluebirdofoz:20200405231713j:plain