【Unity】【シェーダ】フローマップで水流を作る

f:id:halya_11:20180129213647g:plain

フローマップとは?

フローマップとは、水などの「流れ」の方向を定義するためのテクスチャです。

このテクスチャのRチャネルとGチャネルをそれぞれUV方向の流れの強さと捉えるというのがフローマップの考え方です。

今回はこんなテクスチャを作ってみました。

f:id:halya_11:20180129213957p:plain:w300

作り方が下手なので左側がオカシイですが細かいことは気にせず進めます!

フローマップを適用するシェーダを書く - その1

説明を簡易化するために、まず、テクスチャサンプリングを1回だけでフローマップを適用してみます。

プロパティは4つ定義します。

_MainTex ("Texture", 2D) = "white" {}
_FlowMap ("Flow Map", 2D) = "white" {}
_FlowSpeed ("Flow Speed", float) = 1.0
_FlowPower ("Flow Power", float) = 1.0

頂点シェーダではフラグメントシェーダにメインテクスチャのuvを渡し、フラグメントシェーダは次のように記述します。

fixed4 frag (v2f i) : SV_Target
{
 // 1)
 float2 flowDir = tex2D(_FlowMap, i.uv) - 0.5;
 flowDir *= _FlowPower;


 // 2)
 float progress = frac(_Time.x * _FlowSpeed);

 float2 uv = i.uv + flowDir * progress;


 // 3)
 return tex2D(_MainTex, uv);
}

1)ではフローマップのxyの値をそれぞれ-0.5〜0.5の値に変換しています。
これをメインテクスチャのUV値に足すことでフローマップで定義された方向にUVをずらします。

-1.0〜1.0でもいいのでしょうが、メインテクスチャがリピート前提で作られていないとおかしくなりやすい&計算量が少ないので-0.5〜0.5を基準(_FlowPower = 1)にしています。

2)では時間に応じて1)の値を変更しています。
frac() 関数によりprogressには0〜1が入るため、UVに足される値は0から1)の値のレンジとなります。

3)ではこれを使ってテクスチャをサンプリングしています。

結果は次のようになります。

f:id:halya_11:20180129213749g:plain

ちゃんと流れてはいますが、progressに応じてループしていることがバレバレです。

フローマップを適用するシェーダを書く - その2

バレバレ感を防ぐためにフラグメントシェーダを次のように変えます。

fixed4 frag (v2f i) : SV_Target
{
 float2 flowDir = tex2D(_FlowMap, i.uv) - 0.5;
 flowDir *= _FlowPower;


 // 1)
 float progress1 = frac(_Time.x * _FlowSpeed);

 float progress2 = frac(_Time.x * _FlowSpeed + 0.5);
 float2 uv1 = i.uv + flowDir * progress1;
 float2 uv2 = i.uv + flowDir * progress2;
  
 
 // 2)
 float lerpRate = abs((0.5 - progress1) / 0.5);


 
 // 3)
 float4 col1 = tex2D(_MainTex, uv1);

 float4 col2 = tex2D(_MainTex, uv2);
 return lerp(col1, col2, lerpRate);

}

1)でUVをそれぞれ0.5ずつずらして uv1 と uv2 を作成しています。

3)はこれらのUVを用いてテクスチャをサンプリングし、それぞれの色を2)で求める lerpRate で補間します。

この lerpRate を求める2)がポイントです。
progress1 が0または1に近づくほど、lerpRate は1に近づきます。

「progress1 が0または1」の状態とはすなわち、前節でループがバレバレになっていた状態です。
この状態の時に、UVを0.5ずらしてテクスチャマッピングした col2 を使うことで、ループをごまかしています。

描画結果は次のようになります。

f:id:halya_11:20180129213647g:plain

参考にしたサイトなど