UNITY UI简易反向遮罩

附带示例资源文件:https://download.csdn.net/download/qq_55895529/89726994?spm=1001.2014.3001.5503

大致效果:

实现思路:通过ui shader的模板测试功能实现

通过让想要被突出显示的物体优先渲染并写入模板值,而后再让黑色遮罩渲染并判断模板值进行渲染剔除而实现。

所以ui结构如下,DefaultGreen是后面的绿色背景,SphereTargetArea是圆形挖孔,RectangleTargetArea是矩形挖孔,BlackBG是黑色遮罩。

在ui层次上,渲染循序由上到下,所以渲染循序由先到后为:绿色背景-》圆形挖孔-》矩形挖孔-》黑色遮罩。

已知信息:在默认的ui材质中,会写入目标值为0的模板值。且设置为总是通过模板测试,通过后保留原本的模板值。这些信息可以在UI/Default的shader反编译文件中找到,同时选项值的含义可以在unity官方文档Unity - Manual: ShaderLab command: Stencil

中关于Comparison operation values和Stencil operation values的描述中获得解释。

现在就明确了我们的目标,我们接下来所使用的模板值只要都大于0就不会与默认ui产生干扰。

现在我们需要一个无条件写入模板值的shader去写入挖孔处的模板值。

Shader "Custom/GuideMask_Center"
{
    Properties
    {
          _MainTex ("Sprite Texture", 2D) = "white" { }
        
         _Color ("Tint", Color) = (1.000000,1.000000,1.000000,1.000000)
        
         _StencilRef ("_StencilRef", Float) = 0.000000
         _StencilComp ("_StencilComp", Float) = 8.000000
         _StencilPassOp ("_StencilPassOp", Float) = 0.000000
         _StencilFailOp ("_StencilFailOp", Float) = 0.000000
    }
    SubShader
    {
        Tags { "QUEUE"="Transparent" "IGNOREPROJECTOR"="true" "RenderType"="Transparent" "CanUseSpriteAtlas"="true" "PreviewType"="Plane" }

        Blend Zero One
        ZTest [unity_GUIZTestMode]
        ZWrite Off
        Cull Off
        
        Stencil {
           Ref [_StencilRef]
           ReadMask 255
           WriteMask 255
           Comp [_StencilComp]
           Pass [_StencilPassOp]
           Fail [_StencilFailOp]
        }
 
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 2.0

            #include "UnityCG.cginc"

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

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

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float4 _Color;
            float _Radius;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv * _MainTex_ST.xy + _MainTex_ST.zw;
                o.color = v.color;
                return o;
            }

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

                col *= _Color;
                col.a *= i.color.a;

                if(col.a <= 0)
                {
                    discard; // 丢弃透明部分的像素,也就不会在透明部分写入模板值
                }

                clip(col.a);  //  不需要有输出,仅仅做模板处理
                
                return col;
            }
            ENDCG
        }
    }
}

注意一些UI上shader的细节,首先在Tags中设置为透明队列,且"IGNOREPROJECTOR"="true"忽略透视,此外在深度测试试用GUI的测试模式ZTest [unity_GUIZTestMode],并关闭深度写入。

现在填写模板的设置,模板值设定为2(别问为什么不用1,这是因为一会儿遮罩会使用1),
比较操作设置为8,也就是总是会通过测试。通过操作设置为2,也就是会用新的值替换旧的值,那么原本在默认ui下都是0的模板值,就被改写成了2。

这个设置对于矩形挖孔也是一样的,只是换了一张图片。

现在值为2的模板值已经写好了,对于遮罩,仅需要使用模板去对比从而判断是否通过测试即可。

所以shader处理相对更简单

Shader "Custom/GuideMask_Broader"
{
    Properties
    {
         _MainTex ("Sprite Texture", 2D) = "white" { }
        
         _Color ("Tint", Color) = (1.000000,1.000000,1.000000,1.000000)
        
         _StencilRef ("_StencilRef", Float) = 0.000000
         _StencilComp ("_StencilComp", Float) = 8.000000
         _StencilPassOp ("_StencilPassOp", Float) = 0.000000
         _StencilFailOp ("_StencilFailOp", Float) = 0.000000
    
        
    }
    SubShader
    {
        Tags { "QUEUE"="Transparent" "IGNOREPROJECTOR"="true" "RenderType"="Transparent" "CanUseSpriteAtlas"="true" "PreviewType"="Plane" }

        Blend SrcAlpha OneMinusSrcAlpha
        ZTest [unity_GUIZTestMode]
        ZWrite Off
        Cull Off
        
        Stencil {
           Ref [_StencilRef]
           ReadMask 255
           WriteMask 255
           Comp [_StencilComp]
           Pass [_StencilPassOp]
           Fail [_StencilFailOp]
        }
 
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 2.0

            #include "UnityCG.cginc"

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

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

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float4 _Color;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv * _MainTex_ST.xy + _MainTex_ST.zw;
                o.color = v.color;
                return o;
            }

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

对于模板的设置,模板值设置为1,对比操作设置为7,也就是大于等于时通过。那么对于挖空区域在模板缓存中的值为2,自然就无法通过,但对于默认的ui在模板缓存中的值为0,自然可以通过,这样就实现了反选遮罩。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值