Unity 水の揺らぎっぽいポストエフェクト


Unity でポストエフェクト・シェーダを作成する時、参考のためによく GLSL Sandbox を見るのですが、波紋というか水面の揺らぎっぽい表現ができそうなシェーダがあったので Unity に移植してみました。

移植については基本的に Unity エディタで Image Effect Shader を新規で作成して、frag 関数内に GLSL のフラグメントシェーダを移植します。
移植の際、GLSL と Unity(Cg)で使用するキーワードが違いますが、ここ http://www.shibuya24.info/entry/2016/12/15/090000 の対応表を参考にしてキーワードを変換します。
vec 系の型は、適宜 float や fixed に変えてやればいい感じです。
もしこのシェーダをイメージエフェクトではなく、メッシュのマテリアルで使用したい場合は、イメージエフェクト用のテンプレートでは depth が無効になっていますので、ここ https://docs.unity3d.com/jp/540/Manual/SL-CullAndDepth.html を参考に適宜変更します。

今回の移植元のシェーダはテクスチャがないため、gl_FragColor での塗り色を変更していますが、Unity ではレンダリングされる出力画面に揺らぎのエフェクトを追加したかったので、塗り色の変更ではなく UV 座標の変更を行いました。

これを UV ではなく出力される色に計算結果を反映させるとこんな感じになります。

で、下記が Unity に移植して 色ではなく UV に計算結果を反映させるシェーダのコードです。

Shader "ImageEffect/Ripple"
{
	Properties
	{
		_MainTex ("Texture", 2D) = "white" {}
		_Speed ("Speed", Range(1, 60)) = 10
		_Power ("Poewr", Range(0, 1)) = .5
	}
	SubShader
	{
		// No culling or depth
		Cull Off ZWrite Off ZTest Always

		Pass
		{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			
			#include "UnityCG.cginc"


			struct appdata
			{
				float4 vertex : POSITION;
				float2 uv : TEXCOORD0;
			};

			struct v2f
			{
				float2 uv : TEXCOORD0;
				float4 vertex : SV_POSITION;
			};

			v2f vert (appdata v)
			{
				v2f o;
				o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
				o.uv = v.uv;
				return o;
			}


			//
			float wave(float2 uv, float2 emitter, float speed, float phase){
				float dst = distance(uv, emitter);
				return pow((0.5 + 0.5 * sin(dst * phase - _Time.y * speed)), 2.0);
			}


			//
			sampler2D _MainTex;
			float _Speed;
			float _Power;

			fixed4 frag (v2f i) : SV_Target
			{
				float2 position = i.uv;

				float w = wave(position, float2(0.5, 0.5), _Speed, 200.0);
				w += wave(position, float2(0.6, 0.11), _Speed, 20.0);
				w += wave(position, float2(0.9, 0.6), _Speed, 90.0);
				w += wave(position, float2(0.1, 0.84), _Speed, 150.0);
				w += wave(position, float2(0.32, 0.81), _Speed, 150.0);
				w += wave(position, float2(0.16, 0.211), _Speed, 150.0);
				w += wave(position, float2(0.39, 0.46), _Speed, 150.0);
				w += wave(position, float2(0.51, 0.484), _Speed, 150.0);
				w += wave(position, float2(0.732, 0.91), _Speed, 150.0);

				w *= 0.116 * _Power;
				i.uv += w;
				return tex2D(_MainTex, i.uv);

			}
			ENDCG
		}
	}
}

このシェーダをこれ https://www.digifie.jp/blog/archives/1508 でやっているようにポストエフェクトのスクリプトに関連づけてカメラに適用すれば出来上がりです。

ちなみにこのエフェクト、水の表現以外ではこんな感じでも使えます。

今回参考にさせていただいた記事:http://www.shibuya24.info/entry/2016/12/15/090000