Blender で作成したベクトル場を Unity で利用する

# はじめに
　この記事はN高等学校 Advent Calendar 2020 の 20 日目の記事となります。

　私は N 高等学校通学コースプログラミングクラス(愛称はプロクラ、2021度からは通学プログラミングコースに改称)代々木のプログラミングコーチを担当しています。プロクラでは半年に一度の成果発表会、その間は毎月 LT 大会を実施しています。なるべく僕も発表するようにしているのですが、この記事はそのための成果でもあります。

# 目的
　Unity の Visual Effect Graph で使うための Signed Distance Field(SDF) を作りたいと思い、いろいろと調べてみました。すると公式に揃えられているツール類だと Houdini を利用して生成したファイルを Unity にインポートするという方法のようでした。[VFXToolbox](https://github.com/Unity-Technologies/VFXToolbox)に Houdini 用の .hda ファイルが含まれています。

　私は残念ながら Houdini を持っていないので手元のツールでやる方法はないかと調べてみました。結論から言うとやりたかったことは実現できなかったのですが、その間に役に立ちそうな知見が得られたので残しておきます。
![スクリーンショット 2020-12-22 13.40.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13938/83184ddc-6cfb-b51f-8b4f-f4ce38359c9b.png)

## 調査結果
　調べてみると Unity では .vf というファイル形式であれば使えそうだということがわかったので、まずはその形式に持っていくことを考えました。SDF を作りたかったのですが方法が見つからず、代わりに Blender のアドオンを使ってベクトル場を作る方法を見つけました。そのアドオンでは .fga 形式で出力されるので、それから .vf 形式に変換して Unity にインポートすることにしました。
　手順を図で示すと以下のようになります。
![スクリーンショット 2020-12-22 213201.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13938/aa94b8d0-78ba-24f3-612c-72cfb03ff526.png)
　表現方法として SDF はボクセルにスカラー値、ベクトル場はボクセルにベクトル値が割り当てられているという違いのようなので、ひとまずはこの方法で .vf 形式を扱えることを確かめて、改めて SDF に挑戦することにしました。

# Blender でベクトル場を作る
　Blender でベクトル場を作るために [FGA Vector Field Editor](https://github.com/isathar/Blender_UE4_VectorFieldEditor) というアドオンを使うことにしました。使い方に関しては[こちらの YouTube 動画](https://youtu.be/1Z52OQ81Qk0?t=68)が参考になります。

　エクスポートすると .fga というアスキー形式で出力されます。こちらは以下のようなフォーマットになります。一行目に X,Y,Z の分割数、次の二、三行目が境界ボックスの最小値と最大値、以降は各ボクセルのベクトル値が分割数分(x * y * z 個)続きます。
![スクリーンショット 2020-12-22 213644.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13938/414d1d05-25c8-1d26-fc3c-c111c6f562b8.png)
　今回は中心に Force Field を置いて、Strength を `-2.0` として吸い込み型の力場を設置してパーティクルシミュレーション後に、アドオンの機能を使ってベクトル場の計算と正規化をしてエクスポートしました。 
![スクリーンショット 2020-12-21 18.37.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13938/ee8f800a-12ec-793f-b2ac-80ccb01a68e5.png)

# .fga 形式を .vf 形式に変換する
　Unity でインポートするためにアスキー形式の .fga 形式をバイナリ形式の .vf 形式に変換します。

　.vf のフォーマットは[こちら](https://github.com/peeweek/VectorFieldFile/blob/master/README.md)の通りです。

　最初の 4Byte が `FourCC` で `float` なら `'V''F''_''F'` 、`vector` なら `'V''F''_''V'` となります。`float` の場合は 3D テクスチャとしてインポートした際に R 成分のみとなり、SDF に使いたいならこちらとなりそうです。`vector` の場合はインポートした際に RGBA として扱われ力場(Force field)などベクトル場としたい場合はこちらになります。

　次の 6Byte がボリュームの分割数で XYZ それぞれ `ushort` で記録します。

　その次にデータが続きます。`VF_F` なら `float` が `x * y * z` 個のデータが続き、`VF_V` なら `vector(float, float, float)` が `x * y * z * 3` 個のデータが続きます。
![スクリーンショット 2020-12-24 11.16.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13938/9dd0f8c0-d672-032c-aae6-49a8df4e2c2e.png)
　私は C 言語で簡単なコンバータを作って(https://github.com/satoyuichi/fga2vf) 変換を行いました。

# Unity で .vf 形式をインポートする
　Package Manager で Visual Effect Graph をインストールすれば .vf ファイルを 3D テクスチャとしてインポートすることができるので、生成した .vf ファイルを Drag & Drop するだけです。インポート設定は必要に応じて変更してください。私は `Wrap Mode` を `Clamp` にしておらず期待していた動きをせず戸惑いました。

　適当に設定ができたら VFX Graph で `Vector Field Force` ノードの `Vector Field` パラメータとしてインポートした 3D テクスチャを割り当てます。

# おわりに
　一通りワークフローとファイル構造はわかったので、Blender でアドオンでも作ってみようと思っているのですが、すでにありそうな気もしています。どなたかご存知の方いればコメントください。