blenderをpythonのモジュールとして使う


## はじめに

blenderにはpythonが内蔵されており、ほとんどの内部コマンドを制御できます。GUIのコンソールからも呼べますしスクリプトファイルを作っておいて実行することもできます。

あくまで主体がblenderなので、渡されたスクリプトをblender内蔵の python で実行するわけです。--backgroundオプションを渡すとGUIも起動しないので、あたかもpythonスクリプトをCUIで実行するような挙動になります。

```bash
blender --background --python hogehoge.py
```

OSXの場合はblender.appの--argsオプションで引数を渡せばいけるようですね。

```bash
open -a blender.app --args --background --python hogehoge.py
```

これでblenderのpythonによる自動化は十分なのですが、逆に、pythonを主体にblenderを外部モジュールとして呼ぶこともできます。

そんなblenderのpythonモジュールのビルド方法は[こちら](https://wiki.blender.org/wiki/Building_Blender/Other/BlenderAsPyModule)に書いてあります。ビルド過程は退屈なのであとで説明します。まずは使ってみましょう。

## レンダリングしてみる

blenderでは起動時にデフォルトで四角い箱、光源、カメラが作成されるので、起動状態でのレンダリング結果を取得してみましょう。

```python
import bpy

bpy.ops.render.render()
bpy.data.images['Render Result'].save_render(filepath = '/tmp/image.png')
```

のようなhogehoge.pyを用意して、

```bash
$ python3 ./hogehoge.py
```

で/tmp/image.pngが生成されました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/30340/a94162ec-9912-405d-9af2-8634f1c6c0ad.png "image.png")


もちろん、冒頭に説明したようにblenderにhogehoge.pyを渡せば同じことができます。

## Jupyter notebook上で blender

さて、python側の土俵に持ち込んだわけなので、jupyter notebook上とかでも使えることになりますね。となるとレンダリング結果をpythonの配列として取り出してimshowしたいところです。しかし、ちょっと調べた限りでは、どうもファイルを介さずにレンダリング結果を直接取ってくる方法が無いようです。[こちら](https://ammous88.wordpress.com/2015/01/16/blender-access-render-results-pixels-directly-from-python-2/)の方法がいい感じですが、残念ながらblenderのGUIがない状態では機能しませんでした。やむを得ないのでtempfileを介して取ることにしますが、だいぶ負けなかんじですね。

```python
def get_img(size=[480,640]):
    scene = bpy.context.scene
    scene.render.resolution_x = size[1]
    scene.render.resolution_y = size[0]
    scene.render.resolution_percentage = 100
    tmpdir=tempfile.TemporaryDirectory()
    scene.render.filepath=tmpdir.name+"/hoge"
    bpy.ops.render.render(write_still=True)
    img=Image.open(tmpdir.name+"/hoge.png")
    tmpdir.cleanup()
    return img
```

まあともあれ、これを使えば下記のようにJupyter notebook上でレンダリング結果を眺められます。ちょっとずつ移動させながらプロットしてみました。jupyter notebookは[こちら](http://nbviewer.jupyter.org/github/ashitani/jupyter_examples/blob/master/blender.ipynb)で見れます。

![スクリーンショット 2016-10-16 22.14.13.png](https://qiita-image-store.s3.amazonaws.com/0/30340/f6f11f9c-8831-55e0-f261-5c40b703ac86.png "スクリーンショット 2016-10-16 22.14.13.png")

## 使ってみたまとめ

以上のように、python 側からblenderを呼び出すことができました。

しかし、冒頭のようにblenerからpythonを呼ぶのに比べてどういう場合に便利なのでしょう。一つは外部ライブラリとの連携ですが、blender側のpythonでパスを設定するだけな気がします。jupyterで使うのも楽しいですが、ググると他にも方法がありそうです。

結局のところ気分の問題にすぎないのかもしれません。ファイルを介さずに画像のやりとりが出来なかったのはだいぶ痛いです。まあ、使っていて楽しければそれで勝利な気もしますが。

ほんとうは機械学習との組み合わせまでやってみたかったのですが、環境構築で力尽きたので今回のエントリはここまでとします。

これ以降はビルド編です。

## ビルドについて

基本的には[公式](https://wiki.blender.org/index.php/User:Ideasman42/BlenderAsPyModule)に従えばよいのですが、いくつか罠がありましたので記録を残しておきます。下記はOSX El Capitanで行いました。

### ビルド準備

python3で、かつフレームワーク形式でないといけないそうですので、homebrewのpython3を使います。

```
brew install python3
```

blenderのソースを落とします。古いソースだとcmakeがOSや開発環境のバージョンに追従できていなかったりするので、最新ソースでいきます（それはそれで地雷があるかもしれませんが）。

```
blender_dev
+-- blender  (gitから)
+-- lib      (svnから)
+-- build    (ビルド用)
```

のようなフォルダ構成で作業します。libがないとビルドは通りません（ハマりポイント1:後述)。

```bash
mkdir blender_dev
cd blender_dev
git clone git://git.blender.org/blender.git
cd blender
git submodule update --init --recursive
git submodule foreach git checkout master
git submodule foreach git pull --rebase origin master
cd ..
mkdir lib
cd lib
svn checkout https://svn.blender.org/svnroot/bf-blender/trunk/lib/darwin-9.x.universal
cd ..
mkdir build
```

blender/build_files/cmake/platform/platform_apple.cmake
の96行目と210行目で、デフォルトのフレームワークパスが使われているので、brewのpython3のパスを指定します（ハマりポイント２）。

```
#-- line 96 ---
#       set(_py_framework "/Library/Frameworks/Python.framework/Versions/${PYTHON_VERSION}")
        set(_py_framework "/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/")
...
#-- line 210 ---
#   set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} /Library/Frameworks/Python.framework/Versions/${PYTHON_VERSION}/Python")
    set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} /usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/Python")
```

### ビルド＆インストール

さて、やっとビルドです。

```
cd build
cmake \
-D WITH_PYTHON_INSTALL=OFF \
-D WITH_PLAYER=OFF \
-D WITH_PYTHON_MODULE=ON \
../blender/
make
make install
```

make installの実行先はbin以下になっていて、2.78というフォルダに必要なモジュールをコピーするようです。その後、bpy.soと2.78フォルダをsite-packagesにコピーすれば動くとドキュメントには書いてありますが、2.78というフォルダ名ではなくreleaseというフォルダ名でないと動きませんでした(ハマりポイント3:後述）。

```
dest=/usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages
cp ./bin/bpy.so ${dest}
cp -R ./bin/2.78 ${dest}
ln -s ${dest}/2.78 ${dest}/release
```

これでpython3からimport bpyができるようになります。

###　ハマりポイント1

lib以下を作っていないと下記のように怒られました。

```text
CMake Error at build_files/cmake/platform/platform_apple.cmake:36 (message):
  Mac OSX requires pre-compiled libs at:
  '/Users/***/git/blender/../lib/darwin-9.x.universal'
```

[公式ドキュメント](https://wiki.blender.org/index.php/User:Kdawg/Building_Blender/Download_the_dependency_libraries)に書いてますが、プリコンパイルされた依存ライブラリを使えとのことです。まあこれはハマりポイントというよりは公式をちゃんと読めということで。


###　ハマりポイント3

python3からimport bpyすると、下記のように怒られて落ちます。2.78/*へのパスが見つからないようで、ググっても「ちゃんとコピーした？」みたいな回答が大量に見つかります。しましたよ、でもだめなんです。

```
BLT_lang_init: 'locale' data path for translations not found, continuing
bpy: couldnt find 'scripts/modules', blender probably wont start.
Freestyle: couldn't find 'scripts/freestyle/modules', Freestyle won't work properly.
ImportError: No module named 'bpy_types'
ImportError: No module named 'bpy_types'
pyrna_srna_ExternalType: failed to find 'bpy_types' module
ImportError: No module named 'bpy_types'
ImportError: No module named 'bpy_types'
pyrna_srna_ExternalType: failed to find 'bpy_types' module
ImportError: No module named 'bpy_types'
pyrna_srna_ExternalType: failed to find 'bpy_types' module
F1016 18:22:03.065414 2006614016 utilities.cc:322] Check failed: !IsGoogleLoggingInitialized() You called InitGoogleLogging() twice!
```

ドキュメントには2.78というフォルダをコピーしろと書いているのですが、さらに、2.78というフォルダをreleaseというフォルダ名でアクセスできるようにしないとだめでした。