Unity Shader:重叠具有相同模板值的两个图层

Unity Shader: Overlapping two Layers with the same stencil value

我正在尝试编写一个统一的着色器,它将删除底层对象的所有重叠片段。我找到了解决这个问题的不同解决方案,这真的很有帮助。

对我来说,这个 Link () 是最有用的。

但现在我有另一个问题。在图片中,您可以看到 6 个按钮,它们通常具有相同的大小和透明背景。如果这些按钮之一被选中,它会与它的邻居重叠。

下图显示了自定义着色器的外观。我已经通过在背景上开一个洞来显示图像解决了这个问题,但现在我想给这些按钮添加一个文本;如果我再做同样的事情,文字会看起来很粗糙。

Menubutton correct

下面的代码向您展示了我是如何通过在透明盒子上开一个洞来解决我的问题的:

    Shader "Custom/GUI/Mask" {
    Properties
    {
        _Color("Color (white = none)", COLOR) = (1,1,1,1)
        _MainTex("Texture", 2D) = "white" {}
        _CutOff("Cut off", Range(-0.001,1)) = 0.1
    }
    SubShader
    {
        Tags{ "RenderType" = "Transparent" "Queue" = "Geometry" }
        LOD 100

        Blend SrcAlpha OneMinusSrcAlpha
        ZWrite off

        Pass
        {
            Stencil
            {
                Ref 0
                Comp Equal
                Pass IncrSat
                Fail IncrSat
            }

            CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag

                #include "UnityCG.cginc"

                uniform sampler2D _MainTex;
                uniform float4 _MainTex_ST;
                float4 _Color;
                float _CutOff;

                struct appdata
                {
                    float4 vertex : POSITION;
                    float2 uv : TEXCOORD0;
                };

                struct v2f
                {
                    float4 vertex : SV_POSITION;
                    float2 uv : TEXCOORD0;
                };

                v2f vert(appdata v)
                {
                    v2f o;
                    o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                    return o;
                }

                fixed4 frag(v2f i) : SV_Target
                {
                    float4 color = tex2D(_MainTex, i.uv);

                    color.rgb *= _Color.rgb;
                    color.a *= _Color.a;

                    if (color.a <= _CutOff)
                    {
                        discard;
                    }
                    return color;
                }
            ENDCG
        }

        Pass
        {
            Blend SrcAlpha OneMinusSrcAlpha
            ZWrite off

            Stencil
            {
                Ref 1
                Comp Less
            }

            CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag

                #include "UnityCG.cginc"

                float4 _Color;
                uniform sampler2D _MainTex;

                struct appdata
                {
                    float4 vertex : POSITION;
                    float uv : TEXCOORD0;
                };

                struct v2f
                {
                    float4 vertex : SV_POSITION;
                    float uv : TEXCOORD0;
                };

                v2f vert(appdata v)
                {
                    v2f o;
                    o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                    o.uv = v.uv;
                    return o;
                }

                fixed4 frag(v2f i) : SV_Target
                {
                    fixed4 color = tex2D(_MainTex, i.uv);
                    color.a = 0;
                    return color;
                }
            ENDCG
        }

        Pass
        {
            Blend SrcAlpha OneMinusSrcAlpha

            Stencil
            {
                Ref 2
                Comp Less
            }

            CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag

                #include "UnityCG.cginc"

                uniform sampler2D _MainTex;
                float4 _Color;

                struct appdata
                {
                    float4 vertex : POSITION;
                    float uv : TEXCOORD0;
                };

                struct v2f
                {
                    float4 vertex : SV_POSITION;
                    float uv : TEXCOORD0;
                };

                v2f vert(appdata v)
                {
                    v2f o;
                    o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                    o.uv = v.uv;
                    return o;
                }

                fixed4 frag(v2f i) : SV_Target
                {
                    fixed4 color = tex2D(_MainTex, i.uv);
                    color.a = 0;
                    return color;
                }

            ENDCG
        }
    }
}

这张照片显示了没有删除重叠部分的自定义着色器时的样子。在此图片中,您还可以看到,透明背景通常具有 0 的模板值,当它重叠时,该值变为 1。问题是背景上的图像也具有 1 的模板值。所以如果我将删除模板值为 1 的所有对象,我将删除透明背景上的所有图像。顺便说一句,图像和背景包含相同的着色器。

Current view

你能帮我解决这个问题而不在透明盒子上开一个洞吗?切穿选项有问题,如果我有圆形图像,其中有一些透明像素,背景会非常明亮。

非常感谢您的帮助。

终于自己解决了这个问题。对于那些有同样问题的人,这里是解决方案。 我创建了两个不同的着色器。我为背景创建了一个,为背景前面的图片创建了一个。

后台代码如下:

    Shader "Custom/GUI/Background" {
    Properties
    {
        _Color("Color (white = none)", COLOR) = (1,1,1,1)
        _MainTex("Texture", 2D) = "white" {}
        _CutOff("Cut off", Range(-0.001,1)) = 0.1
    }
    SubShader
    {
        Tags{ "RenderType" = "Transparent" "Queue" = "Geometry-100" "LightMode" = "ForwardBase" }
        LOD 100

        Blend SrcAlpha OneMinusSrcAlpha
        ZWrite off

        Pass
        {
            Stencil
            {
                Ref 0
                Comp Equal
                Pass IncrSat
                Fail IncrSat
            }

            CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag

                #include "UnityCG.cginc"

                uniform sampler2D _MainTex;
                uniform float4 _MainTex_ST;
                float4 _Color;
                float _CutOff;

                struct appdata
                {
                    float4 vertex : POSITION;
                    float2 uv : TEXCOORD0;
                };

                struct v2f
                {
                    float4 vertex : SV_POSITION;
                    float2 uv : TEXCOORD0;
                };

                v2f vert(appdata v)
                {
                    v2f o;
                    o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                    return o;
                }

                fixed4 frag(v2f i) : SV_Target
                {
                    float4 color = tex2D(_MainTex, i.uv);

                    color.rgb *= _Color.rgb;
                    color.a *= _Color.a;

                    return color;
                }
            ENDCG
        }
    }
}

这张图片:

    Shader "Custom/GUI/ImageShader"
    {
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
        _Color("Color (white = none)", COLOR) = (1,1,1,1)
    }
    SubShader
    {
        Tags { "RenderType" = "Transparent" }
        LOD 100

            Blend SrcAlpha OneMinusSrcAlpha
            ZWrite off

        Pass
        {
            Stencil
            {
                Ref 0
                Comp Equal
                Pass IncrSat
                Fail IncrSat
            }

        }

        // picture layer
        Pass
        {
            Stencil
            {
                Ref 2
                Comp Equal
            }

            CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                // make fog work
                #pragma multi_compile_fog

                #include "UnityCG.cginc"

                struct appdata
                {
                    float4 vertex : POSITION;
                    float2 uv : TEXCOORD0;
                };

                struct v2f
                {
                    float2 uv : TEXCOORD0;
                    UNITY_FOG_COORDS(1)
                    float4 vertex : SV_POSITION;
                };

                sampler2D _MainTex;
                float4 _MainTex_ST;
                float4 _Color;

                v2f vert(appdata v)
                {
                    v2f o;
                    o.vertex = UnityObjectToClipPos(v.vertex);
                    o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                    UNITY_TRANSFER_FOG(o, o.vertex);
                    return o;
                }

                fixed4 frag(v2f i) : SV_Target
                {
                    // sample the texture
                    fixed4 col = tex2D(_MainTex, i.uv);
                    col.rgb *= _Color.rgb;
                    col.a *= _Color.a;
                    // apply fog
                    UNITY_APPLY_FOG(i.fogCoord, col);
                    return col;
                }
            ENDCG
        }
    }
}

现在的层次结构是:背景在底部,然后是文本,在图像上方。

老实说,我不确定它为什么有效,我知道这不是最好的答案,但我希望我能帮助所有遇到相同或几乎相同问题的人。