unity 3 dはGraphicsを理解する.BlitMultiTap

3215 ワード

unity 3 d公式のImage EffectsパッケージのShaderを勉強すると、この方法が見えるかもしれません.Unityのドキュメントには明確な説明はありません(リンク)
公式の例ではcsでは、このように使用されています.
    // Performs one blur iteration.
    public void FourTapCone (RenderTexture source, RenderTexture dest, int iteration)
    {
        float off = 0.5f + iteration*blurSpread;
        Graphics.BlitMultiTap (source, dest, material,
            new Vector2(-off, -off),
            new Vector2(-off,  off),
            new Vector2( off,  off),
            new Vector2( off, -off)
        );
    }

対応するShaderにSubShaderとこのコードの組み合わせがあります.
    SubShader { 
        Pass {
            ZTest Always Cull Off ZWrite Off Fog { Mode Off }
            SetTexture [_MainTex] {constantColor (0,0,0,0.25) combine texture * constant alpha}
            SetTexture [_MainTex] {constantColor (0,0,0,0.25) combine texture * constant + previous}
            SetTexture [_MainTex] {constantColor (0,0,0,0.25) combine texture * constant + previous}
            SetTexture [_MainTex] {constantColor (0,0,0,0.25) combine texture * constant + previous}
        }
    }

以前、友人が発表した研究によると、以上のコードの意味はGraphics.BlitMultiTapが入力する各オフセット値は、テクスチャサンプリングを1回行い、前のステップのレンダリング結果と重ね合わせます.また、C#にベクトルを追加し、固定パイプラインSubShaderにSetTexture文を1行追加すれば、独自のサンプリング数を追加することもできます.
しかし,プログラマブルパイプラインと結合すると,状況は大きく異なる.公式の例のBlurEffectConeTaps.Shaderには、プログラマブルパイプラインを使用してBlueを実装するSubShaderがもう1つ用意されています.(デフォルトでは、固定パイプラインのSubShaderは以前に選択されていたため、有効になりません.固定パイプラインのSubShaderを注釈すると、プログラマブルパイプラインのSubShaderが有効になります.)このSubShaderで最初に見つかったBlitMultiTapに関するコードは、ここにあるはずです.
    struct v2f {
        float4 pos : POSITION;
        half2 uv : TEXCOORD0;
        half2 taps[4] : TEXCOORD1; 
    };

次にVSで、この4つの配列の各項目に値を付けます.
    half4 _MainTex_TexelSize;
    half4 _BlurOffsets;
    v2f vert( appdata_img v ) {
        v2f o; 
        o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
        o.uv = v.texcoord - _BlurOffsets.xy * _MainTex_TexelSize.xy; // hack, see BlurEffect.cs for the reason for this. let's make a new blur effect soon
        o.taps[0] = o.uv + _MainTex_TexelSize * _BlurOffsets.xy;
        o.taps[1] = o.uv - _MainTex_TexelSize * _BlurOffsets.xy;
        o.taps[2] = o.uv + _MainTex_TexelSize * _BlurOffsets.xy * half2(1,-1);
        o.taps[3] = o.uv - _MainTex_TexelSize * _BlurOffsets.xy * half2(1,-1);
        return o;
    }

最終的にFSで読み取り、使用します.
    sampler2D _MainTex;
    half4 frag(v2f i) : COLOR {
        half4 color = tex2D(_MainTex, i.taps[0]);
        color += tex2D(_MainTex, i.taps[1]);
        color += tex2D(_MainTex, i.taps[2]);
        color += tex2D(_MainTex, i.taps[3]); 
        return color * 0.25;
    }

このシナリオでは、taps[]配列のデータソースはC#コードで指定された4つのオフセットではなく、Shader自身が結合しています.BlurOffsets変数で計算されました._BlurOffsetsは特殊なuniform変数で、C#コードでGraphicsが呼び出された場合.BlitMultiTapが後処理を行うために使用されると、この方法によって入力された最初のoffsetsパラメータが_に割り当てられます.BlurOffsetsのxyは、後続のoffsetsは無視されます.
だから、実はGraphics.BlitMultiTapは、固定パイプラインに合わせて動作する方法です.プログラマブルパイプラインでは、最も基本的な互換性を提供しています.しかし、プログラム可能なパイプラインが提供できる柔軟性については、BlitMultiTapが提供する機能も全く必要ありません.私たちがカスタマイズできるMultiTap方式は、この方法よりはるかに豊富です.現代GPUプログラミングを行う際,我々はそれが時代遅れの方法であると考えることができる.