iOS Metalで流体シミュレーション!

どうも吉村です。

ローレベルグラフィックスAPI、Metal、せっかく出たからには使ってみないわけにはいきません。
せっかくなので、流体シミュレーションにチャレンジします。

さて、大抵のネット上の情報を読むとまず最初に「ナビエ-ストークス方程式」が出てきますが、この記事ではつかいません。
しかしながら、流体のエッセンスさえちゃんとプログラムできれば、
それなりに見えるものは作る事が出来ます。

一応最初に方向性を提示します。
流体シミュレーションの方法には色々なパターンがありますが、
色々試して難易度の低そうだった、

・流体を格子状に分割(オイラー型)
・圧縮可能な流体 (圧縮性流体)

というのでやってみようと思います。

では本題に入ります。
今回はまずデータの持ち方から考えてみます。

前述の通り、オイラー型で進めるため、まずは格子を考えます。
一応図にしておきます。
fuild_key

さて、流体は自由に移動します。が、落ち着いて考えてみると、
・流体の量
・速度 xy
があればなんとなく大丈夫な気がします。

ということで、Metalで浮動小数点テクスチャを作り、r, gの要素に速度を、bの要素に流体の量として格納し、
微小時間ごと更新していけば良さそうです。
こちらも図に示します。
fuild_key 2

データの持ち方はこれで万全でしょう。
なので次はアルゴリズムです。

流体を考える上で、処理のステップを列挙すると、以下のステップを考える事が出来ます。

1、移流
2、圧力
3、外力
4、減衰
5、粘性

ずいぶん多い気がしますが、それぞれ個別に見るとたいした事はありません。
一つ一つ確認していきましょう。
なお、ここからのプログラムはすべて、2次元に広がっているセルのうちの、ある1セルにフォーカスして考えます。
そしてそのセルの周りの8セルのデータを参照して、

1、移流
移流では流体が移動する現象を計算します。
今回は、流体の速度差に着目して、流体の移動を計算します。
こちらも図にすると一目瞭然です。
fuild_key 3

fuild_key 4

2、圧力
圧力では、1格子の中の流体の量によってかかる力を計算します。

fuild_key 5

fuild_key 6

3、外力
これはケースバイケースですし、必要に応じて力を加えるだけなので省きます。

4、減衰
これも単純で、
現在の速度に、「現在の速度に比例する、逆向きの力」を加えることです。

5、粘性
今回は単純に、ガウシアンブラーで流体の情報を平滑化することでよしとしています。
これにより、数値が安定するという副産物があります。

以上のことをふまえて、あとはMetalのシェーダーで実装するだけです。
iOSでこれだけのシミュレーションが出来るなんて感動ものです。

今回のチャレンジのソースコードはこちらにあります。
https://github.com/Ushio/MetalFluidDemo

勉強会でのスライドも公開しています
http://www.slideshare.net/ushiostarfish/metal-fuild-simulation

動画はこちらです。

Metal APIについてはあまり触れませんでしたが、
C++11であることも影響して、
こういった並列計算の記述力はかなり高いです。
またOpenGLよりもスッキリとした構造をしていて、極めて明瞭な構造をしています。
また、テクスチャーをそのまま書き換える事が可能なので、3Dシーンとの連携も簡単に出来てしまいます。

是非みなさんもMetalを使って快適なGPUライフを楽しんでみてはいかがでしょうか?

※環境は Xcode6 beta6, iOS8 beta5です