🧡

[自分用メモ] Blender Python を使ったバッチ処理まとめ

2021/01/15に公開

この記事について

ものすごく重いfbxファイルをバッチ処理で読み込んで加工する必要があり、GUIで使ってるとハングして進まなくなってしまうので、CLIからBlender操作する方法を覚えたのでメモ。

CLIから起動すると、めちゃくちゃ重い処理でもハングせず着々と処理が進むので、どうしようもないときの最終手段として持っておくと便利。
(先日バッチ処理したファイルは6時間くらいかかった)

CLIからのBlenderを実行する方法

blenderをインストールし、以下のようなコマンドを叩くと外部のpythonファイルを読み込んで実行することができる。

blender --background --python main.py


(自分はMacのbrew cask経由でBlenderを入れているので、そうじゃない場合はBlender実行ファイルにパスを通す必要があるかも。自分の環境ではBlenderのパスは/usr/local/bin/blenderに通っていました。)

なおBlenderが利用するPython自体のパスは

/Applications/Blender.app/Contents/Resources/2.90/python/bin/python3.7m

のようなところにあり、システムのPythonとは別のものを利用している。

CLIから使える便利ソースコード群

Pythonファイル(上記の例だとmain.py)を作成し、その中に下記のようなコードを記述するとBlenderがバックグラウンドで開き、自動的に処理を進めてくれる。

特定のフォルダ内のfbxをまとめて読み込み

# bpy = Blender Python。各コマンドはこのモジュールに紐付いている
import bpy
import glob
import os
import time

def bulk_import():
    importDir = f'./original/'

    os.chdir(importDir)
    # fbxファイルの一覧を取得
    paths = glob.glob("*.fbx")
    
    for path in paths:
        bpy.ops.import_scene.fbx(filepath=path, axis_forward="-Z", axis_up="Y")
	
    # このあとにいろんな処理をしていく

fbxをテクスチャ付きで書き出し

def export():
    exportFile = f'./exported.fbx'
    bpy.ops.export_scene.fbx(filepath=exportFile, embed_textures=True, path_mode='COPY')    

メッシュ以外のオブジェクトを削除

def delete_nomesh():
    # Blenderの持つオブジェクトの形式覧
    all_types = ['MESH', 'CURVE', 'SURFACE', 'META', 'FONT', 'HAIR', 'POINTCLOUD', 'VOLUME',
                 'GPENCIL', 'ARMATURE', 'LATTICE', 'EMPTY', 'LIGHT', 'LIGHT_PROBE', 'CAMERA', 'SPEAKER']

    # Mesh以外のオブジェクト種類
    except_mesh = [t for t in all_types if t != 'MESH']
    
    # for文で回して削除
    for _type in except_mesh:
        bpy.ops.object.select_by_type(extend=False, type=_type)
        bpy.ops.object.delete(use_global=False)

メッシュオブジェクトをすべて結合(同一オブジェクトに)

def join_meshes():
    bpy.ops.object.select_all(action='DESELECT')

    mesh_objs = [m for m in bpy.context.scene.objects if m.type == 'MESH']

    for obj in mesh_objs:
        obj.select_set(state=True)
        bpy.context.view_layer.objects.active = obj

    bpy.ops.object.join()

全オブジェクトを削除

def cleanup():
    bpy.ops.object.select_all(action='SELECT')
    bpy.ops.object.delete(use_global=True)

やりたい処理をどう記述するか調べる方法

Blenderは、内部的な処理をPythonで実装しているため、全てのGUI操作の裏側ではPythonが動いています。

つまり、すべてのGUI操作は、特定のPython命令と一対一対応しているということになります。

内部的にどのようなコマンドが動いているかは、Scriptingタブの左下を開くと見ることができます。

ここで、だいたいどんな感じの処理が行われているか把握した上で、左側中段のペインで対話的にコマンドを打ってみて、想定通り動くことが確認できたらPythonファイルに記載していくような流れがおすすめです。

大まかなコマンドがわかったら、公式ドキュメントを読んで引数の意味や種類を調べます。

https://docs.blender.org/api/current/index.html

慣れるまではなかなかうまく行かず難しいですが、一気に作業を効率化できるので、莫大な作業に絶望したらぜひ試してみてください!

Discussion