【Unity】【シェーダ】GrabPassを使って歪みシェーダを作る

f:id:halya_11:20181213221700g:plain

GrabPassを使った歪みを表現するシェーダの実装方法です。

Unity2018.2.0

GrabPass?

GrabPassの説明と基本的な使い方は下記の記事を参照してください。

light11.hatenadiary.com

シェーダ

早速ですがシェーダの実装です。

Shader "GrabPassDistortion" 
{
    Properties 
    {
        _DistortionTex ("Distortion Texture(RG)", 2D)            = "grey" {}
        _DistortionPower ("Distortion Power", Range(0, 1))     = 0
    }
    
    SubShader 
    {
        Tags {"Queue"="Transparent" "RenderType"="Transparent" }
        
        Cull Back 
        ZWrite On
        ZTest LEqual
        ColorMask RGB

        GrabPass { "_GrabPassTexture" }

        Pass {

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

            struct appdata {
                half4 vertex                : POSITION;
                half4 texcoord              : TEXCOORD0;
            };
                
            struct v2f {
                half4 vertex                : SV_POSITION;
                half2 uv                    : TEXCOORD0;
                half4 grabPos               : TEXCOORD1;
            };
            
            sampler2D _DistortionTex;
            half4 _DistortionTex_ST;
            sampler2D _GrabPassTexture;
            half _DistortionPower;

            v2f vert (appdata v)
            {
                v2f o                   = (v2f)0;
                
                o.vertex                = UnityObjectToClipPos(v.vertex);
                o.uv                    = TRANSFORM_TEX(v.texcoord, _DistortionTex);
                o.grabPos               = ComputeGrabScreenPos(o.vertex);

                return o;
            }
            
            fixed4 frag (v2f i) : SV_Target
            {
                // w除算
                half2 uv            = half2(i.grabPos.x / i.grabPos.w, i.grabPos.y / i.grabPos.w);

                // Distortionの値に応じてサンプリングするUVをずらす
                // 0.5019607 = 128/255 = グレーテクスチャの値
                // 厳密な中間値0.5は8bitで表現できないため微妙にずれる(https://enpedia.rxy.jp/wiki/%E5%8F%8D%E8%BB%A2%E8%89%B2)
                // そのためこれを0.5にしてしまうと_DistortionTex未セットの状態で微妙に歪んでしまう
                float2 distortion   = tex2D(_DistortionTex, i.uv).rg - 0.5019607;
                distortion          *= _DistortionPower;

                uv                  = uv + distortion;
                return tex2D(_GrabPassTexture, uv);
            }
            ENDCG
        }
    }
}

_DistortionTexのR値とG値にグレーのテクスチャを入れると歪みが無い状態になります。
_DistortionTexのR値とG値に0.5から離れた値を入れるほど歪みが強くなります(小さい値か大きい値かにより歪む方向が変わります)。

結果

適当なテクスチャを適用するとこんな感じになります。

f:id:halya_11:20181213221700g:plain

テクスチャを変えるといろいろできます。

f:id:halya_11:20181213222421g:plain

_DistortionPowerを変えるとこんな感じ。

f:id:halya_11:20181213222727g:plain

関連

light11.hatenadiary.com

light11.hatenadiary.com