うにてぃブログ

主にUnityとC#に関する記事を書いていきます

【Unity】ShaderLab: GrabPass を使ってみる

GrabPass

描画する際に、現在の画面のテクスチャを取得することができるパス

例えばこういったオブジェクト配置の際に

f:id:hacchi_man:20210807100251p:plain

D で GrabPass を利用すると以下のようなテクスチャが取得できる

f:id:hacchi_man:20210807100346p:plain

テクスチャ自体はこれですが、現在の描画位置に合わせて変換した座標を取得するため

利用する際には以下のようなテクスチャとして利用します

f:id:hacchi_man:20210807100518p:plain:w200

Shader

SubShader 内に、GrabPrass を記述すればテクスチャを取得することができます

この際にテクスチャ名を指定する方法と指定しない方法があり、それによって挙動が変わります

GrabPass

各オブジェクトが個別に GrabTexture を取得します

GrabPass を利用するオブジェクト数が多いとその分メモリが消費されてしまいます

GrabPass { "TextureName" }

そのフレームで最初に呼び出されたオブジェクトのテクスチャを使いまわします

GrabPass を利用するオブジェクト数が変わっても負荷が変わりません

以下のShader を参考にちょっと改変します

ShaderLab: GrabPass - Unity マニュアル

GrabTexture から テクセルを取得する際に tex2 ではなく tex2Dproj を利用していますが

これは射影空間からテクスチャ座標を取得するためのもので、オブジェクトに対して背景テクスチャを

正しく投影したテクセルを取得するために行っているようです

これは自前で変換をする場合は不要のようで、以下のようにすれば tex2D で同等の結果になります

float2 uv = i.grabPos.xy / i.grabPos.w;
half4 col = tex2D(_GrabTexture, uv);
Shader "Custom/GrabPassTest"
{
    SubShader
    {
        // Opaque にすると半透明が GrabTextureに記述されていないので Transparent
        Tags { "Queue" = "Transparent" }
 
        // オブジェクトの後ろの画面を取得
        GrabPass {}
 
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            struct v2f
            {
                float4 grabPos : TEXCOORD0;
                float4 pos : SV_POSITION;
            };

            v2f vert(appdata_base v) {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                // UnityCG.cginc の ComputeGrabScreenPos を使って 
                // 正しいテクスチャ座標を取得します
                o.grabPos = ComputeGrabScreenPos(o.pos);
                return o;
            }

            sampler2D _GrabTexture;

            fixed4 frag(v2f i) : SV_Target
            {
                // 色を反転
                fixed4 color = tex2Dproj(_GrabTexture, i.grabPos);
                return 1 - color;
            }
            ENDCG
        }
    }
}

実行例

先程の Shader を利用して実際に色の変換を行ってみます

f:id:hacchi_man:20210807102645p:plain

するとオブジェクトの範囲だけ色が反転されていることが確認できます

f:id:hacchi_man:20210807102703p:plain

パス数

GrabTexture を取得する必要があるのでこれを利用した場合2パス必要になります

f:id:hacchi_man:20210807103314p:plain