Marble Painterの開発話
前回の記事でご紹介させていただきましたmarble painterについて技術的な開発話です。私は正直、流体に関しては知識0だったので、開発時間のほとんどが勉強でした。
動画[1]:Marble Painterの動作。
コンセプト
姪っ子のため(子供向け)に、web上で動く流体を使ったお絵かきアプリを作るという目標をたてて、企画していきました。
エンジン
それなりに経験のあるUnityにより作成し、WebGL出力を行うこととしました。
流体表現をするにあたって
以下の論文を参考にしました。
Jos Stam氏の2つの論文
・Stable Fluids
・Real-Time Fluid Dynamics for Games
Stable Fluidsの方は、安定した2D、3Dリアルタイム流体シミュレーションについての論文です。最もコンパクトで基礎的な手法らしいので、流体入門者はまずこれを読むと良いとのことです。Real-Time Fluid Dynamics for Gamesは、Stable Fluidsをより実用的に実装することを前提に書かれた論文です。説明も簡略化されておりStable Fluidsよりも実践的な内容になっています。私は流体表現を実装するにあたり、この二つを並行して読みつつ理解を深めていきました。
なお、Stable FluidsはMaya Fluidsなどでも使用されているくらいには非常に有名なアルゴリズムなので、以下のように様々な言語でソースコードが公開されています。(Stable Fluids Githubなどと検索するとたくさん出てきます。)
[1]
https://github.com/finallyjustice/stablefluids
[2]C++での実装例
https://github.com/jrk/stable-fluid
https://github.com/983/Fluid-Simulation
[3]Unityによる実装
https://github.com/keijiro/StableFluids
[4]より複雑なプロダクト。
https://github.com/PavelDoGreat/WebGL-Fluid-Simulation
アルゴリズムの詳細については今回の記事では割愛します。
論文を理解する上では、ベクトルはもちろんのことベクトル場やスカラー場の概念、積分法(ルンゲ・クッタ法等)、ナビエ・ストークス方程式の意味などはあらかじめ勉強しておくと良いかと思います。(今回、私もこれらについて時間をかけて勉強しました。)
流体シミュレーションの実装
さて、いざStableFluidsをUnity C#で書いてみると、それなりに性能の良いPCでも128×128pxでたった15fpsも出ませんでした。
動画[2]:遅いシミュレーション
ここで流体シミュレーションの計算の流れについて簡単に説明します。各ピクセルにおける流体の速度(速度場)を外力や粘性など様々な要素から何回も計算を重ねて求めます。さらに、その速度場から各ピクセルにおける流体にかかる圧力(圧力場)の計算を、正しい解がでるまで何十回もループして補正しつつ求めます。そして圧力場を使って、補正された正しい速度場を求めます。これがたった1フレームの中で行われます。
つまり、速度場と圧力場というテクスチャに対して、何十回ものピクセル処理を1フレームの中で行うことになります。
動画[3]:カラーテクスチャ、圧力場、速度場の動画
(さらに言うと最後に、求められた速度場から、ユーザーが塗ったカラーテクスチャがどこに流れていくかを求めています。)
UnityC#では、1ピクセルずつの処理はシングルスレッドのはずですし、画像を読み込むのにも時間がかかっているようでした。まあつまり、C#が非常に苦手とする分野なため猛烈に処理が遅いのです。
これでは話にならんので、GPUを使って並列処理をやってやろうと[3]を参考に、GPGPU実装しようとしましたが、残念ながらこれはUnityWebglでは動作しませんでした。仕方がないので、1つのテクスチャに対して複数のシェーダーを呼び出す方法で実装しました。(詳細は長くなるので割愛)
画像[1]:C#スクリプトにぶら下がる大量のシェーダー。一つ一つが外力、粘性などを計算する処理になります。
各種お絵かきツールの実装
実はここまでくればもうさほど難しいことはなく、各種お絵かきツールはカラーテクスチャ、速度場、圧力場に対して、計算処理が走る前に値の上書きをするだけです。むしろUIやパラメータの連携などのほうが大変でした。
動画[4]:吸い込み消しゴムツールなど圧力場を計算前に書き換えることで現実には難しい挙動も実現できます。
ダウンロード機能とアップロード機能の実装
ダウンロードに関してはとてもシンプル。Javascriptがちゃんと用意されていました。アップロードに関しては、サーバーなり画像アップローダーを使わないとだめかと思っていたのですが、ローカルファイルを一時的に読むことができる機能がありました。UnityStandaloneFileBrowserというGithubソースを参考に作成しました。
動画[5]:任意の正方形画像を読み込んで、それを混ぜることができます。
カラーピッカー
上記のものを使いました。
さいごに
流体に関してはUnityAssetで公開されているライブラリも多いので、それを使ったほうが早いし効率的とは思いますが、論文を読んで実装する訓練にはちょうど良い題材だったかと思います。ちなみに、ターゲットであった姪っ子は結局プレイしてくれて、楽しんでいました。作戦成功です。
参考文献
非常にわかりやすいナビエ・ストークス方程式の解説
Stable Fluidsの中身に関する日本語の解説
https://shikihuiku.wordpress.com/2013/04/15/stable-fluids/
https://techblog.istyle.co.jp/archives/4515
https://note.com/unshift/n/nceb8d05620d9
http://research.nii.ac.jp/~takayama/teaching/utokyo-iscg-2015/slides/iscg-2015-10-animation3.pdf
https://slidesplayer.net/slide/11190587/
GPU Gems の流体の記事。少しやりかたが違うのでStable Fluidsを理解した後のほうが良いかもしれません
なんだかすごいやつ。非常に難しくわからなかったので、こんなのもあるんだくらいで見てください。
UI周りや、カラーテクスチャ、速度場、圧力場に対する値書き換えは以下のシェーダー例を参考に様々な形状を実現しています。
index.htmlに書き加えてツイッターボタンを作る方法
画像ダウンロード、アップロード周りの参考URL。
https://github.com/gkngkc/UnityStandaloneFileBrowser
http://nakamura001.hatenablog.com/entry/20180201/1517473690
https://junk-box.net/kuyo/index.php/2019/11/24/panorama-dl/
https://psychic-vr-lab.com/blog/unity/unity%E3%81%A7rendertexture%E3%82%92%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AB%E4%BF%9D%E5%AD%98/