水面の歪み - 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;