波動方程式を用いた波紋の作成(2019/11/09修正)

波動方程式を用いた波紋の作成(2019/11/09修正)

Shaderで波動方程式を用いて波紋をシミュレートしてみました。

波動方程式

 波動方程式は以下の通りです。

$$ \frac{1}{s^2}\frac{\partial ^2u}{\partial t^2}=\frac{\partial ^2u}{\partial x^2}+\frac{\partial ^2u}{\partial y^2} $$

離散化した波動方程式

 上記の方程式のままではshaderで処理することはできません。そこで上式を差分化及び離散化すると

$$ \begin{align} u(t+1,x,y)=&s^2\{u(t,x-1,y)+u(t,x+1,y)\\ &+u(t,x,y-1)+u(t,x,y+1)-4u(t,x,y)\}\\ &+2u(t,x,y)-u(t-1,x,y) \end{align} $$

と表せます。この式を用いて波紋をシミュレートします。

Shader

波紋計算用shader

 波紋をシミュレートするためのShaderはこちらです。色は0~1の値をとります。しかし、波の上下を表すにはマイナスの値も必要です。そこで、2を掛けたのちに1を引くことで0~1を-1~1へ変更し、計算しています。また、テクスチャの赤色に計算結果を、緑色に一つ前の状態を書き込んでいます。

画像合成用shader

 以前、記事にした画像合成用shaderを利用しています。詳しくはこちらに掲載しています。このshaderで任意の画像を合成することで、水面に外力を加えることができます。そのため、そこから新たな波紋が発生します。

初期化用shader

 レンダーテクスチャを初期化する際に使用するshaderです。

Script

 このScriptを平面のオブジェクトにアタッチすることで、その平面に波紋を発生させることができます。waveMatには波紋計算用のshaderを選択したMaterialを、matPaintには画像合成用のshaderを選択したMaterialを、mat_gray_texにはレンダーテクスチャの初期化用shaderを選択したMaterialを割り当てます。texBlushには外力を与えるための画像を割り当てます。ここでは、Default-Particleを使用しました。
 左クリックをした場所のUV座標を検出しています。そして、その場所へGraphics.BlitでtexBlushを画像合成用のMaterialで波紋用のRenderTextureに合成しています。次に、このRenderTextureを、Graphics.Blitによって波紋を計算するためのMaterialへ渡します。これによって得られたRenderTextureをオブジェクトに設定されたMaterialへ渡し、波紋を表示しています。波紋の表示には、渡されたテクスチャの赤色を白黒に表示するshaderを作成し、使用しています。

波紋が広がるエリアの設定

 このままでは、四角い領域でしか波紋が作成できません。そこで、自由な領域で波紋を発生させるために波紋計算用shaderへ新たに処理を追加しました。波紋を発生させたい場所を白色、発生させたくない場所を黒色としたテクスチャを新たに作成し、このテクスチャによって波紋が発生する領域を変更できるようにしました。

実行結果

 BlushSizeで力を加えるための画像の大きさを変更できます。Phasevelocityは波紋が伝わる速さ、Attenuationは減衰率を調整できます。また、WaveAreaで波紋が発生する領域を変更することができます。Initializeボタンを押すと、波紋の発生していない状態に戻すことができます。


修正履歴

Scriptの修正

・レンダーテクスチャ(rTex)を初期化際に0.5を書き込めていなかった問題の修正(詳しくはこちら

・RenderTexture.GetTemporaryでテクスチャフォーマットを指定していなかったため、floatで処理できていなかった問題の修正

参考サイト

しゅみぷろ:任意の点がモデル表面上に存在する場合にその位置のUVを算出する
Processingでシミュレーション~波動方程式

【Unite 2017 Tokyo】スマートフォンでどこまでできる?3Dゲームをぐりぐり動かすテクニック講座