Blender : Pythonによる処理の自動化

By | 2017年8月31日

脱出ゲーム制作の作業を効率化

脱出ゲームでは部屋にオブジェクトを配置した後、色々な角度にカメラを配置してレンダリングする必要があります。レンダリング中は操作の必要が無くひたすら待つだけです。ですので作業を自動化して夜間にまとめてレンダリングできたら便利だなと思ったわけです。

BlenderはPythonを利用した自由度の高い操作が可能らしいので今回挑戦しました。

特別な起動方法

Blenderには「Python Console」というインターフェイスがあるので、標準出力の結果はここに表示されるものと思っていました。しかし実際はOSのコンソールに出力されます。WindowsではBlenderのメニューからOSのコンソールを起動できるのですがMacではできません。MacではコンソールからBlenderを起動することで、BLenderからの出力を得ることができます。
出力先を探すのにすごく時間がかかりました。Blender内にコンソールがあるのに何故OSのコンソールに出力するの?
→参考:公式サイト「The Console Window(英語のみ)」

0830_d

情報ウインドウの隠れた機能

Python自体はメジャーな言語なので情報はネットにたくさんあります。しかしBlenderで利用する場合は、Blender特有の機能を把握しなければなりません(パッケージ名はbpy)。
公式サイトでBlender固有の機能を説明しています。
→参考:公式サイト「Python マニュアル」 英語サイトへ丸投げしているので日本語情報は無い…。

しかしBlenderは公式サイトに頼らずとも簡単に関数やプロパティを知ることができるのです!。普段は最小化されている情報ウインドウですが、これを拡げると実際に操作した内容がPythonのコードとして表示されるのです。下の画像はマテリアルの設定でEmissionのstrengthを5に変更した際に表示されたコードです。 1行目はマテリアルのタブを選択したときのコードで、2行目が値を変更したときのコード。

0830_a 0830_b

BlenderのCyclesモードはノードで複雑なシェーダーを作成できるので、それを制御するコードも複雑になります。もし、こんなコードを公式サイトのマニュアルだけを頼りに作成しなければならないと考えたら恐ろしいです…。
Blenderはバージョンアップ毎にPythonのまわりが変更されることが多いらしくネットで情報が探しにくいらしいので、この仕組みは非常に助かります!!

CSVの読込

今回はカメラの座標とライトの強さのリストをCSVファイルとして外部に持ち、その順番通りにレンダリングして画像を自動的に保存するような処理を実現します。ということでPythonのCSV読込について調べたらBlenderでの利用法を説明しているサイトがあったのでメモ。

How to read a csv file and use the values as x and y points in blender?
You can use the csv library to read and parse CSVs. (英語)

PythonにはCSVを扱うモジュールがあり、Blenderでも問題なく利用できるようです。

実際にやってみた

利用するCSVは以下のような感じでカメラの座標と角度、ライトの強さを3箇所分用意しました。

0830_c

で実行するpythonコードは以下。CSVのモジュールがあるので予想以上にシンプルに書けました。
オブジェクトの角度の設定はUI上では「度」ですがスクリプトでは「ラジアン」で設定します。


import bpy, os, math, csv

filePath = '/Users/designdrill/Desktop/studyBlender/02_python/camera.csv'
with open(filePath) as csvfile:
	reader = csv.reader(csvfile)
	for i, row in enumerate(reader):
		if i == 0: continue #-------------------------Skip column titles
		print(row[0])
		bpy.data.objects['Camera'].location.x = float(row[1])
		bpy.data.objects['Camera'].location.y = float(row[2])
		bpy.data.objects['Camera'].location.z = float(row[3])
		bpy.data.objects['Camera'].rotation_euler.x = (float(row[4])*math.pi)/180
		bpy.data.objects['Camera'].rotation_euler.y = (float(row[5])*math.pi)/180
		bpy.data.objects['Camera'].rotation_euler.z = (float(row[6])*math.pi)/180
		bpy.data.materials['camera_light'].node_tree.nodes["Emission"].inputs[1].default_value = float(row[7])
		bpy.ops.render.render()
		bpy.data.images['Render Result'].save_render(filepath = os.path.dirname(bpy.data.filepath) + '/image'+row[0]+'.png')
非同期処理ではない

最近では非同期処理が当たり前すぎて、上記の処理がちょっと違和感でした(いや何も間違っていないのですが…)。赤字の部分でレンダリングをしていてレンダリングが終わるまで次の行は実行されません(当たり前なのですが…)。折角なのでPythonでの非同期処理について調べたのでメモ。以下のサイトが詳しいです。

Pythonにおける非同期処理: asyncio逆引きリファレンス
Pythonにはthreading、multiprocessing、asyncioとどれも並列処理に使えそうなパッケージが3つあります。

でもって、以下は実際にコードを走らせたときの動画です。

プログレスバー

今回の例では順次レンダリング画像を保存していくので「どこまで処理が進んだか」は書き出されたファイルを見れば分かります。しかし1つの処理が非常に時間がかかる場合はプログレスバーが必要だと思うので、ネットで情報を探しておきました。

How to show to the user a progression in a script?
Progress of script can also be printed and updated with sys module to the console:(英語)

おしまい


コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

Time limit is exhausted. Please reload the CAPTCHA.