水面の歪み - saitocastel1900/UnityShader GitHub Wiki
-
水面より下にあるオブジェクトを歪ませる
-
URPだとGrabPassは使えないので、_CameraOpaqueTextureを使って歪みを再現する
-
_CameraOpaqueTextureを使用するためには、事前にパイプラインに設定する必要がある
- _CameraOpaqueTextureは、パスが実行されるまでのレンダリング結果を取得できる変数
- _CameraDepthTextureは、深度バッファの生データを取得できる変数
sampler2D _CameraOpaqueTexture
sampler2D _CameraDepthTexture
- 歪ませること自体は深度値を使わなくてもできるので、まずはシンプルにやってみる
//歪みの量を計算
float2 distoration = sin(i.uv.y * 50 + _Time.w) * _DistortionPower;
//_CameraOpaqueTextureはスクリーン座標なので、スクリーン座標をもとに歪ませるテクスチャを定義。しかし、このままだと板に投影された時の空間座標が異なるので、最後にビュー座標に直す
float2 uv = (i.scrPos.xy + distoration) / i.scrPos.w;
//ビュー座標で歪ませたレンダリング結果を表示
return tex2D(_CameraOpaqueTexture,uv) * _MainColor;
- 座標系を治さないとこうなります
- このままで十分いい感じだけど、歪ませたレンダリング結果を載せているので、全体が歪んでしまっている。これを修正するために、深度情報を活用して歪ませる部分を判断する
深度テクスチャの参照にはそのためのスクリーン座標が必要なので、ComputeScreenPosでスクリーン座標を求める
o.scrPos = ComputeScreenPos(o.vertex);
///深度値はスクリーン座標をもとに取得為るので、サンプリングするUVにスクリーン座標を入れている
float4 depthUV = i.grabPos;
//
depthUV.xy = i.grabPos.xy + distortion * 1.5f;
//深度テクスチャをサンプリング
//デプスバッファを取得する
float backgroundDepth = LinearEyeDepth(SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(depthUV)));
//スクリーン座標をプロジェクション座標に直することで、深度値を取得している
float surfaceDepth = UNITY_Z_0_FAR_FROM_CLIPSPACE(i.scrPos.z);
//saturate()でマイナスにならないように、0~1に固定している
//これで、塗るか塗らないかを決めている(0~1)
float depthDiff = saturate(backgroundDepth - surfaceDepth);
//uv座標をプロジェクション座標に直すため、wで除算している
float2 uv = (i.grabPos.xy + distortion * depthDiff) / i.grabPos.w;