ATMWRIによるUE5の記録

Unreal Engine 5 を使い始めました

BlenderへPLATEAUのモデルを2時間40分かけてインポートした話

昨日は、はじめてBlender pythonを使用してimportした4~5000個ほどのオブジェクトを7つのオブジェクトにまとめ、マテリアルのセット、UV unwrapといった作業を自動化した。
いつかfbxのimportも自動化したいな思っていたが暇だったのでやってみた。

1.ソース

pythonの作法とか知らないので自分で分かればいいやレベルの汚ソース。target_dirFPXAssetsは綴りを間違えているがあえて放置している。

import glob
import bpy
import math

target_dir="D:\\FPXAssets\\13100_tokyo23-ku_2020_fbx_3_op\\bldg\\lod1"
search_key="533925"
path_list=glob.glob(target_dir + '\\' + search_key + '*')

# コレクションの検索用関数
def recurLayerCollection(layerColl, collName):
    found = None
    if (layerColl.name == collName):
        return layerColl
    for layer in layerColl.children:
        found = recurLayerCollection(layer, collName)
        if found:
            return found

# fbxデータ内のオブジェクトをランダムで7個にする関数
def randomJoinObjects():
    divNum = [0.14, 0.17, 0.2, 0.25, 0.33, 0.5, 1]
    sd = 1

    for div in divNum:
        bpy.ops.object.select_random(ratio=div, seed=sd)
        
        # Join先のオブジェクトを有効化
        target = bpy.context.selected_objects[0]
        bpy.context.view_layer.objects.active = target
        bpy.ops.object.join()
        
        # UV unwrap処理
        if(target.data.uv_layers=='None'):
                bpy.ops.mesh.uv_texture_add()
            
        bpy.ops.object.editmode_toggle()
        bpy.ops.uv.smart_project(angle_limit=math.radians(66), island_margin=0, area_weight=0, correct_aspect=True, scale_to_bounds=False)
        bpy.ops.object.editmode_toggle()
        
        # マテリアルのセット
        if target.data.materials:
            target.data.materials[0] = bpy.data.materials[sd]
        else:
            target.data.materials.append(bpy.data.materials[sd])
        
        # hideしてワンセット終わり
        for o in bpy.context.selected_objects:
            o.hide_set(True)
            
        # ランダムシード値の更新
        sd += 1
        

for f in path_list:
    # 新しいコレクションの名前を作成
    i=f.find(search_key)
    new_col_name=f[(i+len(search_key)):(i+len(search_key)+2)]

    # コレクションを作成
    new_col = bpy.data.collections.new(new_col_name)
    bpy.context.scene.collection.children.link(new_col)

    # 作成したコレクションのアクティブ化
    layer_collection=bpy.context.view_layer.layer_collection
    layer_col = recurLayerCollection(layer_collection, new_col.name)
    bpy.context.view_layer.active_layer_collection = layer_col

    # FBXファイルのインポート
    bpy.ops.import_scene.fbx(filepath=f)

    # ランダムに7つのオブジェクトへマージする処理
    # import後はすべて選択されているので選択を解除しておく
    bpy.ops.object.select_all(action='DESELECT')
    randomJoinObjects()

2. ソースのメモ

モデルの加工部分は前の記事で書いたので、今回はそれ以外の部分について気になった点をメモしておく。

  • Collectionをアクティブにするのがめんどい
    すぐ思いつく簡単な方法が通らなかったので検索。↑のdef recurLayerCollection(layerColl, collName)は以下を参考にした。
    https://blender.stackexchange.com/
    Change active collection
  • UV unwrapのパラメータがラジアン
    画面上はオイラーアングル?っぽいけどAPIではfloat0~1.xxまでとか書いている。ラジアンらしいのでmath.radians()を使った。
  • オブジェクトの選択解除どうする?
    bpy.ops.object.select_all(action='DESELECT')

テストした

Test用に用意したfbxファイルx4をblenderpythonでインポート
インポートからの加工が一瞬で終わって少し感動したが、これで楽できると思ったら大間違いだった。

3.実際に使ってみた

PLATEAUのLOD1の建物をエリア単位でインポートしてみる。昨日手作業でインポートした大田区エリアは30ファイルあり、およそ1時間程度を要した。今回選択した目黒・品川エリアはファイル数は96と多いが自動化したのだからと期待は大きかった。

スクリプト実行でBlenderは即応答なしの状態へ入り不安に襲われる。タスクマネージャを起動してCPU,RAMの使用状況が変動していることからフリーズでは無いと判断。アニメを見たりして気を紛らわす

1時間後コンビニにでかけて帰ってきてもまだ応答がない。仕方がないのでパソコンの前でヨガを始める。呼吸に集中していると、時折PCのファンの回転数が上昇してBlenderの息吹を感じた。まだフリーズしていない。

ヨガが終わって買ってきたポテチを食べようとした頃にようやく完了した。開始からおよそ2時間40分、信じてよかった。

Blenderで96ファイル分のモデルをインポートして処理した結果

4.まとめ

今回は成功したからいいものの、失敗していたら相当落ち込む。一度にインポートするファイル数を減らすかコンソールにログを出力して正常に動作していることを確認できる仕組みを取り入れることができるのならやってみたい。