【Unity】【シェーダ】GrabPassの説明とシェーダの実装例

GrabPassの説明とシェーダの実装例です。

Unity2018.2.0

GrabPass?

GrabPassは、このパスが実行される時点のレンダリング結果を取得できる特殊なパスです。
次のように書くことで使えます。

SubShader 
{
    // 描画結果をテクスチャに書き込みたいタイミングに応じてQueueを調整する
    Tags { "Queue" = "Transparent" }

    // GrabPass
    GrabPass { }

    Pass {
        /*** 略 ***/ 
        
        // GrabPass以降のパスに_GrabTextureという変数を定義しておくとGrabPassの結果が取得できる
        sampler2D _GrabTexture;

        /*** 略 ***/ 
    }
}

ただしこの処理は重いので、何回も呼ぶときには次のように書きます。
最初に呼ばれたときのレンダリング結果がすべてのパスで使いまわされますが、
1Frameにつき1回しか処理が行われないので処理負荷が小さくなります。

SubShader 
{
    // 描画結果をテクスチャに書き込みたいタイミングに応じてQueueを調整する
    Tags { "Queue" = "Transparent" }

    // GrabPassをテクスチャ名を指定して定義
    GrabPass { "_GrabPassTexture" }

    Pass {
        /*** 略 ***/ 
        
        // GrabPass以降のパスに指定した名前のテクスチャを定義しておくとGrabPassの結果が取得できる
        sampler2D _GrabPassTexture;

        /*** 略 ***/ 
    }
}

実装例

例として、GrabPassで取得したテクスチャを_Shift分だけずらすシェーダを実装します。

Shader "GrabPassDistortion" 
{
    Properties 
    {
        _Shift ("Shift", Range(0.0, 1.0))      = 0
    }
    
    SubShader 
    {
        // 描画結果をテクスチャに書き込みたいタイミングに応じてQueueを調整する
        Tags { "Queue" = "Transparent" }
        
        GrabPass { "_GrabPassTexture" }

        Pass {

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

            sampler2D _GrabPassTexture;
            float _Shift;

            struct v2f {
                half4 vertex                : SV_POSITION;
                half4 grabPos               : TEXCOORD0;
            };

            v2f vert (float4 vertex : POSITION)
            {
                v2f o                   = (v2f)0;
                // まずUnityObjectToClipPos
                o.vertex                = UnityObjectToClipPos(vertex);
                // GrabPassのテクスチャをサンプリングするUV座標はComputeGrabScreenPosで求める
                o.grabPos               = ComputeGrabScreenPos(o.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                // w除算が必要なのでtex2Dprojを使う
                return tex2Dproj(_GrabPassTexture, i.grabPos + _Shift);
            }

            ENDCG
        }
    }
}

説明はコメントの通りです。
フラグメントシェーダのw除算についてはこの記事では説明しませんが、次の記事で説明しています。

light11.hatenadiary.com

light11.hatenadiary.com

結果

Quadにこのシェーダを適用すると次のような結果になります。

f:id:halya_11:20181202171702g:plain

レンダリング結果を使って処理ができていることがわかります。

関連

light11.hatenadiary.com

light11.hatenadiary.com

参考

docs.unity3d.com