遮罩自定义模糊(UITextureMask)
这个在写的过程中遇到了一个问题,效果实在UI层,然后我使用了Mask组件。写完之后发现,怎么测都不对,检查代码逻辑也没问题。一直到第二天,无意间发现了解决方案,只需要将Mask替换成RectMask2D就能让我的代码跑起来。顿时间眼里充满了激动的泪水………………
父节点要使用RectMask2D,该Pass才能正常获取Mask的Rect信息。
思路:
IN.worldPosition为顶点着色器中拿到的模型空间的坐标,应该对应的是该节点的LocalPosition,我是打印的Text提交的顶点信息,才有这个结论。
_ClipRect是从RectMask2D传递进来的裁剪框的窗口范围(float4)。
_AphaTex是存储Apha渐变信息的遮罩贴图,一般是单通道图。
如下图,结合IN.worldPosition与_ClipRect的关系,将映射到([0,1],[0,1])范围内,然后再对设定的_AphaTex采样,获取对应的R值,最后将R值信息相乘赋值给color.a
效果预览:
遮罩的R通道图
?这是图片的应用
?文字的应用
贴图信息:
256*256的单通道贴图即可,大点也可以,反正Unity都会做归一化处理。RGBA ETC2,因为没找美术要单通道图,所以就找了一个辨识度高的图片,我这里只使用了是R通道。
代码:
Shader "Unlit/UITextureMask"
{
Properties
{
[PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
_Color ("Tint", Color) = (1,1,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
_AphaTex ("Texture", 2D) = "white" {}
[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 __ UNITY_UI_CLIP_RECT
#pragma multi_compile __ 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 worldPosition : TEXCOORD1;
UNITY_VERTEX_OUTPUT_STEREO
};
sampler2D _MainTex;
sampler2D _AphaTex;
fixed4 _Color;
fixed4 _TextureSampleAdd;
float4 _ClipRect;
float4 _MainTex_ST;
v2f vert(appdata_t v)
{
v2f OUT;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
OUT.worldPosition = v.vertex;
OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
OUT.color = v.color * _Color;
return OUT;
}
fixed4 frag(v2f IN) : SV_Target
{
half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
#ifdef UNITY_UI_CLIP_RECT
float c = UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
color.a *= c;
if (c > 0)
{
//裁剪窗口内,使用R通道来叠加apha
float2 diffPos = IN.worldPosition.xy - _ClipRect.xy;
float2 texcoord = diffPos / (_ClipRect.zw - _ClipRect.xy);
half4 aphaColor = tex2D(_AphaTex, texcoord);
color.a *= aphaColor.r;
}
#endif
#ifdef UNITY_UI_ALPHACLIP
clip (color.a - 0.001);
#endif
return color;
}
ENDCG
}
}
}
自适应边框模糊(UISoftMask)
选定边界范围,并设置透明度渐变来实现。
实现主要是参考雨松的这篇文章,但雨松的这边文章主要是针对MeshRender,3D模型而来,经过测试发现,在UGUI中,实现这种方案,,只需要应用材质,使用RectMask2D组件即可,不需要再。 ?
思路:
1. (position.xy - clipRect.xy) / float2(_ClipSoftX, _ClipSoftY) * step(clipRect.xy, position.xy);
2. (clipRect.zw - position.xy) / float2(_ClipSoftX, _ClipSoftY) * step(position.xy, clipRect.zw);
3. 2 * outA*(1 - outA)*0.5f + outA * outA;
通过公式1和2来在边缘的有效距离内(_ClipSoftX, _ClipSoftY)设置[0-1]的渐变值,这是线性曲线变化。
然后通过公式3,来对上述线性值进行二阶曲线的扰动,最后相乘赋值给color.a
代码:
Shader "Unlit/SoftMask"
{
Properties
{
[PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
_AphaTex("Texture", 2D) = "white" {}
_Color("Tint", Color) = (1,1,1,1)
_ColorMask("Color Mask", Float) = 15
_ClipSoftX ("Clip Soft X", Float) = 15
_ClipSoftY ("Clip Soft Y", Float) = 15
[Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip("Use Alpha Clip", Float) = 0
}
SubShader
{
Tags
{
"Queue" = "Transparent"
"IgnoreProjector" = "True"
"RenderType" = "Transparent"
"PreviewType" = "Plane"
"CanUseSpriteAtlas" = "True"
}
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 worldPosition : TEXCOORD1;
UNITY_VERTEX_OUTPUT_STEREO
};
sampler2D _MainTex;
sampler2D _AphaTex;
fixed4 _Color;
fixed4 _TextureSampleAdd;
float4 _ClipRect;
float4 _MainTex_ST;
v2f vert(appdata_t v)
{
v2f OUT;
UNITY_SETUP_INSTANCE_ID(v);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
OUT.worldPosition = v.vertex;
OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
OUT.color = v.color * _Color;
return OUT;
}
float _ClipSoftX;
float _ClipSoftY;
inline float SoftUnityGet2DClipping(in float2 position, in float4 clipRect)
{
float2 xy = (position.xy - clipRect.xy) / float2(_ClipSoftX, _ClipSoftY) * step(clipRect.xy, position.xy);
float2 zw = (clipRect.zw - position.xy) / float2(_ClipSoftX, _ClipSoftY) * step(position.xy, clipRect.zw);
float2 factor = clamp(0, zw, xy);
return saturate(min(factor.x, factor.y));
}
fixed4 frag(v2f IN) : SV_Target
{
half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
//color.a *= SoftUnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
float outA = SoftUnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
color.a *= 2 * outA*(1 - outA)*0.5f + outA * outA;
#ifdef UNITY_UI_ALPHACLIP
clip(color.a - 0.001);
#endif
return color;
}
ENDCG
}
}
}
使用方法
1.目标节点父系节点中要使用RectMask2D组件
2.拖拽材质(UISoftMask/UITextureMask),到目标组件中(Text/Image)
资源地址
Unity2018.4.1f1 Package 提取码:d4u3?
|