经过测试,即使图片有不透明到透明的过渡,传统的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
}
}
}