UnityShader学习笔记[二百九十九]UGUI中的Mask遮罩半透明Shader

经过测试,即使图片有不透明到透明的过渡,传统的UGUI的Mask组件也会认为只要有一丁点透明度,就完全显示,而不是显示半透明过渡。

网上搜了一会也没搜到类似的网页

打算用UIDefault来改一个可以根据图片透明度来显示半透明通道的用于UI的Shader

本身对图片使用的Default做过几次修改,对这个有些熟悉,而不是对Mask进行修改。

对Mask的Shader进行修改可能会更加容易,因为他可能只是读取到有透明度就用1来表示遮罩值,如果是这样将遮罩值直接用透明度表示可能就可以。后面发现mask不是通过shader实现是UGUI内部类实现。

这里的修改是直接替换图片的,所以用于比较多的图片的ScrollView的显示区域时候,每个都要替换才能有相同的效果,会麻烦一些。

首先获取Default,他默认是透明度混合的写法,默认的Image一般也是会有透明度渐变的。所以可以在此基础更改

然后是将该Shader发给GPT,根据 Unity学习shader笔记[一百八十五]用于UI的shader特性总结 列出具体修改点,得到初版代码

帮我修改这段代码,Property增加一个表示透明度的图片,以及表示起始点和范围的vector变量。 然后Shader中物体根据其局部坐标与这个vector变量的起始点的差值,用这个差值与vector变量的表示宽高的分量的值进行除法得到归一化值,用这个归一化值代表UV采样透明度的图片,用透明度的图片与UIDefault本身计算好的透明度的图片相乘,来得到最后的透明度。

初版在位置上有问题

UI使用的shader里面的模型坐标系原点是在屏幕中心 ,模型坐标的单位是屏幕分辨率。

这个特性和UI的Anchor与pivot无关,不管他俩设置成什么值都是这样的一个特性。

所以这里算范围的时候是以屏幕中心为原点,向右向上是正方向。移动一下位置可以正常显示。将宽高调成UI的宽高。

因为共用一个材质,所以对于在ScrollView里范围里面的所有item。将起始点和范围调成ScrollView的起始点和范围就可以了。

先将ScrollView的UI放到Canvas下, anchor都设置成0.5.然后可以直接赋值。赋值好位置以后再随便调anchor和层级。

对宽高位置时候pivot要在左下角,

原因是下图这样,算显示位置的时候才对。

看效果时候 这里临时调成slice,宽高才能铺满image.否则有些图片会本身宽高限制。

缺少下面的代码

csharp 复制代码
alphaUV.x = clamp(alphaUV.x, 0, 1);
alphaUV.y = clamp(alphaUV.y, 0, 1);
                

uv超过1的部分会自动对1取余再采样 结果是重复平铺,所以大于1的部分就限制为1.这样大于1的部分因为uv是1,采样是边缘透明。不会显示出来。

csharp 复制代码
 float2 delta = localPos - start;
 float2 alphaUV = delta / size;
csharp 复制代码
// Unity built-in shader source. Copyright (c) 2016 Unity Technologies.
// MIT license (see license.txt)

Shader "Custom/UITransparentMask"
{
    Properties
    {
        [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
        _Color ("Tint", Color) = (1,1,1,1)

        // ===== 新增 =====
        _AlphaTex ("Alpha Texture", 2D) = "white" {}
        _AlphaRect ("Alpha Start(xy) Size(zw)", Vector) = (0,0,1,1)

        _StencilComp ("Stencil Comparison", Float) = 8
        _Stencil ("Stencil ID", Float) = 0
        _StencilOp ("Stencil Operation", Float) = 0
        _StencilWriteMask ("Stencil Write Mask", Float) = 255
        _StencilReadMask ("Stencil Read Mask", Float) = 255

        _ColorMask ("Color Mask", Float) = 15

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

    SubShader
    {
        Tags
        {
            "Queue"="Transparent"
            "IgnoreProjector"="True"
            "RenderType"="Transparent"
            "PreviewType"="Plane"
            "CanUseSpriteAtlas"="True"
        }

        Stencil
        {
            Ref [_Stencil]
            Comp [_StencilComp]
            Pass [_StencilOp]
            ReadMask [_StencilReadMask]
            WriteMask [_StencilWriteMask]
        }

        Cull Off
        Lighting Off
        ZWrite Off
        ZTest [unity_GUIZTestMode]
        Blend SrcAlpha OneMinusSrcAlpha
        ColorMask [_ColorMask]

        Pass
        {
            Name "Default"
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 2.0

            #include "UnityCG.cginc"
            #include "UnityUI.cginc"

            #pragma multi_compile_local _ UNITY_UI_CLIP_RECT
            #pragma multi_compile_local _ UNITY_UI_ALPHACLIP

            struct appdata_t
            {
                float4 vertex   : POSITION;
                float4 color    : COLOR;
                float2 texcoord : TEXCOORD0;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct v2f
            {
                float4 vertex   : SV_POSITION;
                fixed4 color    : COLOR;
                float2 texcoord : TEXCOORD0;
                float4 posOS : TEXCOORD1; // 实际是 UI 局部坐标
                UNITY_VERTEX_OUTPUT_STEREO
            };

            sampler2D _MainTex;
            sampler2D _AlphaTex;

            fixed4 _Color;
            fixed4 _TextureSampleAdd;
            float4 _ClipRect;
            float4 _MainTex_ST;

            float4 _AlphaRect; // xy = start, zw = size

            v2f vert(appdata_t v)
            {
                v2f OUT;
                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);

                OUT.posOS = v.vertex;
                OUT.vertex = UnityObjectToClipPos(OUT.posOS);

                OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
                OUT.color = v.color * _Color;
                return OUT;
            }

            fixed4 frag(v2f IN) : SV_Target
            {
                // ===== UI Default 颜色 =====
                half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;

                // ===== Alpha 贴图计算 =====
                float2 localPos = IN.posOS.xy;

                float2 start = _AlphaRect.xy;
                float2 size  = max(_AlphaRect.zw, 0.0001);

                float2 delta = localPos - start;
                float2 alphaUV = delta / size;

                
                alphaUV.x = clamp(alphaUV.x, 0, 1);
                alphaUV.y = clamp(alphaUV.y, 0, 1);
                
                // 如果需要限制范围,可打开这一行
                // alphaUV = saturate(alphaUV);

                half alphaMask = tex2D(_AlphaTex, alphaUV).a;
                color.a *= alphaMask;

                // ===== UI 裁剪 =====
                #ifdef UNITY_UI_CLIP_RECT
                color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
                #endif

                #ifdef UNITY_UI_ALPHACLIP
                clip (color.a - 0.001);
                #endif

                return color;
            }
            ENDCG
        }
    }
}
相关推荐
啦哈拉哈3 小时前
【Python】知识点零碎学习4
python·学习·算法
HyperAI超神经3 小时前
【vLLM 学习】Rlhf Utils
人工智能·深度学习·学习·机器学习·ai编程·vllm
P.H. Infinity4 小时前
【QLIB】三、学习层(一)
学习
June bug4 小时前
【实习笔记】客户端基础技术
笔记·macos·cocoa
laplace01234 小时前
第八章 agent记忆与检索 下
数据库·人工智能·笔记·agent·rag
茜子.Java4 小时前
分享一个输入 allure --version 报错解决方式
学习
狐574 小时前
2026-01-19-牛客每日一题-阅读理解
笔记·算法·牛客
不会代码的小猴4 小时前
Linux环境编程第一天笔记
linux·笔记
航行的pig5 小时前
Python基础学习笔记
笔记·python