うにてぃブログ

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

【Shader】オブジェクトを重ねた数によって色を変える

Stencil Shader を利用して、オブジェクトの重なり具合に応じて色を変える実装をしてみます

オブジェクトのShader

Stencil Pass を利用して オブジェクトがある箇所のステンシルバッファの値を加算していきます

こうすることでオブジェクトが重なっている箇所ではステンシルバッファの値が 2 や 3 などにすることができます

また、このオブジェクト自体は 描画する必要が無いため ColorMask 0 を指定して、色の描画をしないようにしています

Shader "Custom/Element"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
 
    SubShader
    {
        Tags {
            "RenderType"="Opaque"
            "Queue"="Geometry+1"
        }
 
        Pass
        {
            Stencil {
                Comp Always
                Pass IncrSat
            }
 
            ColorMask 0
 
            CGPROGRAM
            #pragma vertex vert_img
            #pragma fragment frag

            #include "UnityCG.cginc"

            fixed4 frag (v2f_img i) : SV_Target
            {
                return fixed4(0, 0, 0, 1);
            }
            ENDCG
        }
    }
}

オブジェクトの重なりを描画する Shader

こちらの Shader は Stencil ReadMask を利用して、ステンシルバッファの値が奇数のときのみ描画するようにしてあります

奇数は最下位ビットが必ず 1 になるので 1 とビットマスクした結果が 1になれば奇数です

プログラム的に書くと (num & 0x01) == 0x01 となります

※ 偶数の場合は Ref 0 ReadMask 1

Shader "Custom/OddStencil"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Color ("Color", Color) = (1, 1, 1, 1)
    }
    SubShader
    {
        Tags {
            "RenderType"="Opaque"
            "Queue"="Geometry+1"
        }

        Pass
        {
            Stencil {
                Ref 1
                ReadMask 1
                Comp Equal
            }

            CGPROGRAM
            #pragma vertex vert_img
            #pragma fragment frag

            #include "UnityCG.cginc"

            float4 _Color;

            fixed4 frag (v2f_img i) : SV_Target
            {
                return _Color;
            }
            ENDCG
        }
    }
}

実際に動かしてみる

オブジェクトの Stencil と 奇数の Stencil を利用して実際に動かしてみます

f:id:hacchi_man:20210211125927g:plain

重なった数が奇数の場合色がついてることが確認できます

問題点

四角い画像ならいいのですが、アルファが入っている画像だといい感じに表示することができませんでした

もしかしたら現在の描画している色を調べる方法があるかもしれないので、気が向いたら対応してみたいと思います