Unity Mask Shader

在使用Unity时,会发现Mask组件,使用像素比较小的图作为Mask会出现锯齿,看到网上有使用Shader去处理。

这里的原理是:从遮罩纹理中采样透明度来修改片元的透明度, 遮罩的圆形之外的部分透明度为0, 该过度的地方也有不同透明度, 这样就能正确混合也能正确起到遮罩的效果.

使用Mask组件的效果

 使用Shader效果:

 放在一起对比:

 具体Shader代码

Shader "Custom/CustomMask"
{
   Properties{
      [PerRendererData] _Maintex("Sprite Texture",2D) = "white" {}
      _MaskTex("Mask Texture",2D) = "white"{}
      _Color("Tint",Color) = (1,1,1,1)
      
      _ColorMask("Color Mask",Range(0,15)) = 15

      [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip",float) = 0
   }

   SubShader{
      Tags{
         "Queue" = "Transparent"
         "IgnoreProjector" = "True"
         "RenderType" = "Transparent"
         "PreviewType" = "Plane"//PreviewType 指示材质检视面板预览应如何显示材质。默认情况下,材质为球体,Plane 显示2D Skybox 显示天空盒
         "CanUseSpriteAtlas" = "True"
      }

      Cull Off
      Lighting Off
      ZWrite Off
      ZTest [unity_GUIZTestMode]//unity_GUIZTestMode Unity的测试模式 适应不同的设备 保证流畅度
      Blend SrcAlpha oneMinusSrcAlpha
      ColorMask[_ColorMask]
      
      Pass{

         Name "CostomMask"
         CGPROGRAM                              //使用CG语言编写着色器程序
         #pragma vertex vert                    //顶点着色器
         #pragma fragment frag                  //片段着色器
         #pragma target 2.0                     //支持渲染目标

         #include "UnityCG.cginc"               //包含Unity内置的CG函数和变量
         #include "UnityUI.cginc"               //包含Unity UI相关的CG函数和变量

         #pragma multi_compile __ UNITY_UI_ALPHACLIP // 根据是否用Alpha Clipping 编译多个版本的着色器代码

         //定义输入数据结构
         struct appdata_t
         {
            float4 vertex : POSITION;              //顶点坐标
            float4 color :COLOR;                  //顶点颜色
            float2 texcoord:TEXCOORD0;             //纹理坐标
            UNITY_VERTEX_INPUT_INSTANCE_ID         //实例ID
         };
         //定义输出数据结构
         struct v2f
         {
            float4 vertex : SV_POSITION;          //裁剪空间坐标
            float4 color : COLOR;                 //片段颜色
            float2 texcoord : TEXCOORD0;          //纹理坐标
            float4 worldPosition : TEXCOORD1;     //世界坐标
            UNITY_VERTEX_OUTPUT_STEREO            //立体视图信息
         };

         fixed4 _Color;
         fixed4 _TextureSampleAdd;
         float4 _ClipRect;

         //顶点着色器
         v2f vert(appdata_t IN)
         {
            v2f OUT;
            UNITY_SETUP_INSTANCE_ID(IN);                          //设置实例ID
            UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);           //初始化立体视图信息
            OUT.worldPosition = IN.vertex;                        //记录世界坐标
            OUT.vertex = UnityObjectToClipPos(OUT.worldPosition); //转换为裁剪空间坐标
            OUT.texcoord = IN.texcoord;                           //传递纹理坐标

            OUT.color = IN.color * _Color;                          //传递顶点颜色并应用颜色调整
            return OUT;
         }

         sampler2D _Maintex;     //Sprite纹理
         sampler2D _MaskTex;     //遮罩纹理

         float _OneMinusSaturability;    //饱和度
        // 片段着色器函数
         fixed4 frag(v2f IN) : SV_TARGET
         {
            half4 color = (tex2D(_Maintex,IN.texcoord)+_TextureSampleAdd);    // 采样Sprite的纹理并加上采样增量
            if(IN.color.r<0.0001 && IN.color.g<0.0001&&IN.color.b>0.0004){    // 判断颜色是否为蓝色
               float gray = dot(color.rgb,float3(0.2125,0.7154,0.0721));       // 将颜色转换为灰度值
               color.rgb = float3(gray,gray,gray);                              // 将颜色设置为灰度值
            }
            else
            {
               color *= IN.color;
               if(_OneMinusSaturability>0.05)                                                              // 判断饱和度是否大于0.05
               {
                  float gray = dot(color.rgb,float3(0.2125,0.7154,0.0721));                               // 将颜色转换为灰度值
                  color.rgb = lerp(float3(gray, gray, gray), color.rgb, 1 - _OneMinusSaturability);       // 插值计算颜色
               }
            }

            color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);                                // 计算Alpha值
            color.a *= tex2D(_MaskTex,IN.texcoord).a;// 乘以遮罩的Alpha值

            #ifdef UNITY_UI_ALPHACLIP // 如果定义了UNITY_UI_ALPHACLIP
            clip(color.a-0.001); // 进行Alpha剪裁
            #endif

            return color; // 返回颜色
         }
         ENDCG
      }
   }
   
}

使用shader的好处:

在使用系统自带的Mask,会增加DrallCall。

 从图片上看只有两个图片,为啥会有三个DrallCall,这个是因为:绘制完Mask所有节点之后 需要把Stencil复原,增加了一次DrawCall。

使用Shader可以不会增加DrallCall:

猜你喜欢

转载自blog.csdn.net/qq_33515628/article/details/130207046