2018年7月8日日曜日

Blenderから自作レンダラー向けに設定をエクスポート

blender_exporting_settings

Blenderから自作レンダラー向けに設定をエクスポート

こんにちは。 このページは レイトレ合宿6 の記事です.

今年もレイトレ合宿の日が近くなってきて どんなシーンをレンダリングしようかと考えている頃ではないでしょうか。 そこで、 1 Blenderで扱うシーンの設定を自作のレンダラー向けにエクスポートできるように してみます。 Blenderからエクスポートすることの利点は、

  • Blenderという強力なGUIツールを用いて効率良くシーンを作成できる
  • Cyclesレンダラーなどの他のエンジンと同じ設定でレンダリングすることで、レンダリング結果を比較できる

などが挙げられます。

デモファイルのダウンロード

設定をエクスポートするに当たって、 Blenderの公式サイトで配布されている ヘリコプターデモ “scene-Helicopter-27.Blend” を用います。

Blenderデモ

以下の画像の場所からダウンロードできます。感謝!。

Blenderの設定

設定をエクスポートする前に、Blenderの設定を確認します。

1. RenderEngineの設定

使用するレンダリングエンジンを選択します。 ここは Cycles Render を選択します (ヘリコプターデモの場合は既にCycles Renderが選択されています)。

2. Dimensionsの設定

出力する画像の解像度を設定します。 Resolution の項目を100%にし、XYに画像の解像度を設定します。

3. Samplingの設定

Pattern で使用する乱数のサンプラーを選択し、 SettingsS に乱数のシード値を指定しします。 SamplesRender に1ピクセル当りのレイのサンプル数を指定します。

4. LightPathsの設定

様々な経路長のパスを考慮するため、Full Global Illumination を選択します。

5. PostProcessingの設定

画像処理前のレンダリング画像を取得するため、 Post Processingのチェックを全て外しておきます。

6. Surfaceの設定

Cyclesエンジンの初期設定で、うっすらとした環境光が設定されている場合があります。 意図しない光源が設定されていると比較の際に困るので、 BackgroundStrength0 になっているか確認しておきます。

7. Performanceの設定

パフォーマンスの比較を行う場合は、Threads で使用するスレッド数を指定します。

リファレンスの作成

以上の設定を確認してレンダリングを行います。

自作レンダラーとの比較のために、マテリアルの設定をもう少しシンプルにしておきます。

これで、設定をエクスポートする準備が整いました。

Blenderエクスポーターの作成

Blenderから設定をエクスポートするツールを作成します。

BlenderはPythonインタプリタを内蔵しており、 Blender内でPythonスクリプトを実行することができます。 そこで、Blenderから設定をエクスポートするPythonスクリプトを作成してみます。

Pythonスクリプトの実行

Pythonスクリプトは、Blender起動時に引数として渡して実行することができます。 試しにスクリプトを実行してみます。 以下は.Blendファイルのファイル名を表示するスクリプトです。

端末を開いて、Blenderに引数として渡して実行します。

% blender --background Helicopter.blend --python exporter1.py
Read blend: Helicopter.blend

## FileName: Helicopter

Blender quit

Blenderの実行ファイルの場所は、Windowsなら C:\Program Files\Blender Foundation\Blender\blender.exe、 macOSなら/Applications/Blender/blender.app/Contents/MacOS/blenderにあると思います。

--background オプションを指定すると、BlenderのGUIを起動せずに Pythonスクリプトを実行することができます。

実行する際のポイントは、Helicopter.blendよりも後に--python exporter1.py を指定することです。 Helicopter.blendの設定が読み込まれた後にスクリプトが実行されます。

スクリプト内でimport bpy を実行することで、BlenderのAPIを利用できるようになります。 利用できるAPIの詳細は Blender Documentation Python API で参照できます。

シーンデータの取得

.Blendファイルを読み込んだ際の各種設定は、 bpy.data に記録されます (bpy.dataの構造については BlendData を参照して下さい)。

各シーンの情報については bpy.data.scenes に記録されています。 (bpy.data.scenesの構造については Scene を参照して下さい)。

特定のシーンデータを取得する場合はシーン名を指定することで取得できます。 シーン名は Outliner で確認できます。

以下はSceneという名前のシーンから情報を取得するスクリプトの例です。

最初に、 scene = bpy.data.scenes[scene_name] で欲しいシーン情報を取得し、 シーンの各種情報を取得しています。 上のスクリプトでは、情報を標準出力に出力しているだけですが、 実際には自作レンダラーのフォーマットに加工してファイルに出力します。

実行結果は以下のようになります。

% blender --background Helicopter.blend --python exporter2.py
Read blend: Helicopter.blend

Image resolution: 1920 x 1080
Sampler: CORRELATED_MULTI_JITTER
Sampler seed: 123456789
Threads: 4
Render samples: 512

Blender quit

もし欲しい情報のAPIがわからない場合は、 BlenderのGUI上でその情報を編集するためのボタンやメニューの上に マウスカーソルを置いてみて下さい。 しばらくするとポップアップが現れて、その情報を利用するためのAPIを表示してくれます。

カメラ

シーンのアクティブカメラの情報は、scene.camera に入っています。

scene.camera 自体は Object 構造になっており、 カメラの位置や回転などの情報が入っています。 scene.camera.data にはカメラの画角やレンズなどの情報が入っています (Camera を参照して下さい)。

実行結果は以下のようになります。

% blender --background Helicopter.blend --python exporter3.py
Read blend: Helicopter.blend

X axis rotation: 4.169113636016846 radian.
Y axis rotation: 3.1490345001220703 radian.
Z axis rotation: 3.9584245681762695 radian.
position: (1.483912467956543, -1.3075470924377441, 1.6609470844268799)
Horizontal field of view: 0.8575560450553894
Vertical field of view: 0.5033799409866333

Blender quit

オブジェクト

シーン内のオブジェクトのデータは scene.objects に入っています (各オブジェクトの構造は Object を参照して下さい)。 例えば、シーン内のオブジェクト名を全て表示するスクリプトは、

のようになります。

試しに上画像のOutlinerのシーンで実行してみると、

blender --background TestScene.blend --python exporter4.py
Read blend: TestScene.blend

ObjectB
ObjectA
ObjectA-2
ObjectA-1
Lamp
Camera

Blender quit

scene.objects にはオブジェクト同士の親子関係に関わらず全てのオブジェクトが 入っています。 親子関係を考慮する場合は、

のように書くことができます。 obj.parent には親となるオブジェクトが入っており (トップレベルの場合は None)、 obj.children は子となるオブジェクトの配列(子がいない場合は要素を持たない配列) となっており、これらを用いて親子階層を意識した処理を書くことができます。

実行結果は

% blender --background TestScene.blend --python exporter5.py
Read blend: TestScene.blend
ObjectB
ObjectA
  child node: ObjectA-1
  child node: ObjectA-2
Lamp
Camera

Blender quit

となります。

次は、オブジェクト内の情報をエクスポートしてみます。

obj.type を見ることで、どんな種類のオブジェクトなのかがわかります (例えば ‘MESH’、‘CURVE’、’CAMERA’など。Type of Object)。 また、この種類の違いによって、 obj.data の構造も異なります (’MESH’なら Mesh 、’CURVE’なら Curve など)。

bpy.ops.export_scene.obj はオブジェクトを .obj 形式で書き出すAPIです (Export Scene Operators を参照)。 オブジェクトの種類毎に処理を変えるのは大変なので、 ここでは bpy.ops.export_scene.obj を用いて ’MESH’や’CURVE’などのオブジェクトは全て .obj 形式に書き出すようにしました。

以下は実行結果の一部を切り出したものです。

% blender --background Helicopter.blend --python exporter6.py
Read blend: Helicopter.blend

...

Bolt+Nut.011
  Material name: Metal
  Material index: 3
    (  0.0409 sec |   0.0000 sec) OBJ Export path: 'Bolt+Nut.011.obj'
          (  0.2900 sec |   0.2481 sec) Finished writing geometry of 'Bolt+Nut.011'.
      (  0.2964 sec |   0.2550 sec) Finished exporting geometry, now exporting materials
      (  0.2964 sec |   0.2550 sec) OBJ Export Finished

Progress: 100.00%

...

Blender quit

オブジェクト“Bolt+Nut.011”が“Bolt+Nut.011.obj”として書き出されました。 自作レンダラーでは、このobjファイルを読み込むように設定をエクスポートしています。

マテリアル

マテリアルの情報は bpy.data.materials に入っています (各マテリアルの構造は Material を参照して下さい)。 Blenderのマテリアルデータは複雑で、また、自作レンダラーのマテリアルデータとは 取るパラメータも異なるため、 マテリアルデータに関してはエクスポートは行わず後から手動で設定するようにしました。

Cyclesレンダラーと自作レンダラーの比較

エクスポートした設定を自作レンダラーに読み込ませて実際にレンダリングしてみました。

以下はCyclesレンダラーとの比較になります。

上画像がCyclesレンダラーでレンダリングした画像で、 下画像が自作レンダラーでレンダリングした画像です。 カメラ設定やオブジェクトの場所は一致させられたと思います。

しかし、レンダラー間でのマテリアルが取るパラメータの違いや係数の違い、 色空間設定の違いから、 結果を完全に一致させるにはまだ工夫が必要だと感じました。 一応今のままでも簡単な比較には使えそうです。

私のレンダラー向けのエクスポーターは、 blender_scene_exporter.py にあります。 参考にどうぞ。

参考

  1. Blender Documentation Python API: https://docs.blender.org/api/current/

  1. この記事内で使用したBlenderのバージョンは 2.79b です。