![1ba4d67fae52d464d2a2cf197a5fe7cc.png](https://img-blog.csdnimg.cn/img_convert/1ba4d67fae52d464d2a2cf197a5fe7cc.png)
手头一个项目在做UI流光特效的时候发现一个很普遍的问题:特效穿透
之前的项目中,虽然也有类似特效。但是特效所在的页面不会被遮住,或者有新页面时特效所在的页面会被隐藏,所以可以忽略不计。
这次的特效稍有不同,特效所在的页面是最底层ui,始终存在且不做隐藏,所以之前的缩小或者置顶的方式便无法使用了。
为了解决这个问题,我网上查阅了一下,找到了几种解决方法:
1.改被穿透UI的层级
2.降低特效层级
3.新页面用新摄像头
4.出现高层UI时隐藏特效
改被穿透UI的层级
修改被穿透的UI层级(renderer queue、order in layer等)可以解决这个问题,但同时也带来了另一个问题。就是所有渲染层级高于该特效的UI都需要添加一个UI材质去提高渲染层级,否则要么被穿透,要么被已经提高了层级的其他UI所遮挡。
降低特效层级
这个不可取,因为特效的渲染层级一旦改低,哪怕只是-1,就会被底部UI所遮挡。那么我们要做的就是将包括特效在内的所有应该低于特效的UI的渲染层级都一起降低,才不会出现特效被底层UI遮挡的情况。
新页面用新摄像头。
这个可以解决问题且比上面两个方便多了,但新页面用新摄像头总有一种大炮打蚊子的感觉,所以也,没使用这个方法。
出现高层UI时隐藏特效
这个方法就见仁见智了,方法的问题主要有两个
- 需要监听所有页面生成和移除,然后判断和当前页面的关系,然后再去控制特效显示与否。
- 如果上面的页面是个带半透明遮罩的弹窗,那么是可以通过半透明遮罩看到特效的突然关闭与显示的,看起来怪怪的。
上面的4个解决方案就是我大致找到的,应该还有更好的方案,但我确实没找到。
我想了一下后,发现这个流光本身并不复杂,应该可以通过 UI图片 做偏移来模拟这个效果。
创建了一个材质并改为UI-Default之后发现偏移所用的Offset参数并未开方,所以我根据之前看的相关教程对UI-Default做了一些修改。
Shader "UI/Default-Offset"
{
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
_HorizontalAmount ("Horizontal Amount", Float) = 4 //新增变量
_VerticalAmount ("Vertical Amount", Float) = 4 //新增变量
_Speed ("Speed", Range(1, 100)) = 30 //新增变量
[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_ALPHACLIP
struct appdata_t
{
float4 vertex : POSITION;
float4 color : COLOR;
float2 texcoord : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
half2 texcoord : TEXCOORD0;
float4 worldPosition : TEXCOORD1;
};
fixed4 _Color;
fixed4 _TextureSampleAdd;
float4 _ClipRect;
v2f vert(appdata_t IN)
{
v2f OUT;
OUT.worldPosition = IN.vertex;
OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
OUT.texcoord = IN.texcoord;
#ifdef UNITY_HALF_TEXEL_OFFSET
OUT.vertex.xy += (_ScreenParams.zw-1.0) * float2(-1,1) * OUT.vertex.w;
#endif
OUT.color = IN.color * _Color;
return OUT;
}
sampler2D _MainTex;
float4 _MainTex_ST;
float _HorizontalAmount; //引用
float _VerticalAmount; //引用
float _Speed; //引用
fixed4 frag(v2f IN) : SV_Target
{
//======修改的内容=========
float time = floor(_Time.y * _Speed);
float row = floor(time / _HorizontalAmount);
float column = time - row * _HorizontalAmount;
half2 uv = IN.texcoord + half2(column, -row);
uv.x /= _HorizontalAmount;
uv.y /= _VerticalAmount;
half4 color = (tex2D(_MainTex, uv) + _TextureSampleAdd) * IN.color;
//===================
color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
#ifdef UNITY_UI_ALPHACLIP
clip (color.a - 0.001);
#endif
return color;
}
ENDCG
}
}
}
- 将该shader设置为ui材质的shader,路径为“UI/Default-Offset”
- HorizontalAmount 控制水平移速,1为静止(建议每次增加0.01
- VerticalAmount 控制垂直移速,1为静止(建议每次增加0.01
- Speed 控制流光速度
![c15c9ccf9f0200158b75bfc8c6e7beb6.png](https://img-blog.csdnimg.cn/img_convert/c15c9ccf9f0200158b75bfc8c6e7beb6.png)
原理是通过时间变化来自动控制采样偏移来模拟流光效果,图片建议两侧不要有被裁切的流光,最高能左右接的上去。