265 lines
10 KiB
GLSL
265 lines
10 KiB
GLSL
// UIMask:UI Mask 粒子/特效 shader —— 加色与普通混合共用一个 shader
|
||
//
|
||
// 混合模式在材质面板上是一个下拉框 "_BlendMode"(加色 Additive / 普通混合 AlphaBlend)。
|
||
// 它由 Assets/Shaders/Editor/UIMaskBlendMode.cs([UIMaskBlendMode] 绘制器)映射到真正的 Blend 状态:
|
||
// 加色(Additive): _SrcBlend = 5 (SrcAlpha) _DstBlend = 1 (One)
|
||
// 普通混合(AlphaBlend):_SrcBlend = 5 (SrcAlpha) _DstBlend = 10 (OneMinusSrcAlpha)
|
||
// 渲染面同理:[UIMaskRenderFace] 下拉映射到隐藏属性 _Cull(双面=0,只渲染后面=1,只渲染前面=2)。
|
||
// _SrcBlend / _DstBlend / _Cull 是隐藏属性,由下拉框自动写入,不要手动改。
|
||
// Blend 是固定功能状态,不参与 shader 变体表,所以切换混合模式不产生额外变体。
|
||
// 面向美术:程序/技术类参数一律用 [HideInInspector] 隐藏(混合模式内部值、Stencil 组、
|
||
// 顶点 Mask 翻转),需要时由程序控制,材质面板只留艺术参数。
|
||
Shader "VFX/VFX" {
|
||
Properties {
|
||
[UIMaskBlendMode] _BlendMode ("混合模式", Float) = 0
|
||
[HideInInspector] _SrcBlend ("Src Blend", Float) = 5
|
||
[HideInInspector] _DstBlend ("Dst Blend", Float) = 1
|
||
[UIMaskRenderFace] _RenderFace ("渲染面", Float) = 2
|
||
[HideInInspector] _Cull ("Cull", Float) = 0
|
||
[HDR]_TintColor ("着色", Color) = (0.5,0.5,0.5,0.5)
|
||
_GlowScale("发光强度", float) = 1
|
||
_AlphaScale("透明度", float) = 1
|
||
_MainTex ("主贴图", 2D) = "white" {}
|
||
[Toggle] _UseUvAni("启用", Float) = 0
|
||
_SpeedU("U 速度", Float) = 0
|
||
_SpeedV("V 速度", Float) = 0
|
||
[Toggle] _UseUvDistortion("启用", Float) = 0
|
||
_UVNoiseTex("噪声贴图", 2D) = "black" {}
|
||
_Distortion ("扰动量", Float) = 0
|
||
_NoiseScroll ("噪声滚动 (XY 速度 / ZW 强度)", Vector) = (0,0,1,1)
|
||
[Toggle] _UseMask("启用", Float) = 0
|
||
[Toggle] _UseMaskUvAni("UV 滚动", Float) = 0
|
||
_Mask("遮罩贴图", 2D) = "white" {}
|
||
[UIMaskChannel] _MaskChannel("通道", Float) = 3
|
||
_MaskSpeedU("U 速度", Float) = 0
|
||
_MaskSpeedV("V 速度", Float) = 0
|
||
[Toggle] _UseDissolve("启用", Float) = 0
|
||
_DissolveTex ("溶解贴图", 2D) = "white" {}
|
||
[UIMaskChannel] _DissolveChannel("通道", Float) = 3
|
||
_Dissolve ("溶解进度", Range(0, 1.01)) = 0
|
||
_DissolveWidth ("溶解宽度", Range(0, 1)) = 0
|
||
[Toggle] _UseUIMaskClip("启用", Float) = 0
|
||
_ClipRect("裁切矩形 (由 Mask / RectMask2D 控制)", Vector) = (-1, -1, 1, 1)
|
||
[Toggle] _UseVertexMask("启用", Float) = 0
|
||
_VertexOffset ("方向与范围", Vector) = (0,0,1,1)
|
||
// 程序专用:顶点 Mask 的翻转,由程序设置
|
||
[HideInInspector] _VertexFlipX ("程序专用", Float) = 1
|
||
// required for UI.Mask —— 这几个由 Unity 的 Mask / RectMask2D 在运行时写入,不需要美术看到
|
||
[HideInInspector] _StencilComp("Stencil Comparison", Float) = 8
|
||
[HideInInspector] _Stencil("Stencil ID", Float) = 0
|
||
[HideInInspector] _StencilOp("Stencil Operation", Float) = 0
|
||
[HideInInspector] _StencilWriteMask("Stencil Write Mask", Float) = 255
|
||
[HideInInspector] _StencilReadMask("Stencil Read Mask", Float) = 255
|
||
[HideInInspector] _ColorMask("Color Mask", Float) = 15
|
||
}
|
||
|
||
CustomEditor "UIMaskShaderGUI"
|
||
|
||
Category {
|
||
Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" }
|
||
Blend [_SrcBlend][_DstBlend]
|
||
Cull [_Cull] Lighting Off ZWrite Off
|
||
|
||
SubShader {
|
||
Stencil
|
||
{
|
||
Ref[_Stencil]
|
||
Comp[_StencilComp]
|
||
Pass[_StencilOp]
|
||
ReadMask[_StencilReadMask]
|
||
WriteMask[_StencilWriteMask]
|
||
}
|
||
ColorMask[_ColorMask]
|
||
|
||
Pass {
|
||
|
||
CGPROGRAM
|
||
#pragma vertex vert
|
||
#pragma fragment frag
|
||
#pragma target 2.0
|
||
|
||
// 全部使用 shader_feature(按材质用到的组合裁剪),不要改成 multi_compile
|
||
#pragma shader_feature _USEMASK_ON
|
||
#pragma shader_feature _USEMASKUVANI_ON
|
||
#pragma shader_feature _USEUVANI_ON
|
||
#pragma shader_feature _USEUVDISTORTION_ON
|
||
#pragma shader_feature _USEDISSOLVE_ON
|
||
#pragma shader_feature _USEUIMASKCLIP_ON
|
||
#pragma shader_feature _USEVERTEXMASK_ON
|
||
|
||
// 不声明 multi_compile_fog:UNITY_FOG_* 宏在无雾关键字时展开为空,
|
||
// 原来的"_UseReceiveFog"开关勾了也不会有任何效果,故已移除。
|
||
|
||
#include "UnityCG.cginc"
|
||
#include "UnityUI.cginc"
|
||
|
||
sampler2D _MainTex;
|
||
fixed4 _TintColor;
|
||
|
||
#if _USEMASK_ON
|
||
sampler2D _Mask;
|
||
fixed4 _Mask_ST;
|
||
float _MaskChannel;
|
||
#if _USEMASKUVANI_ON
|
||
float _MaskSpeedU;
|
||
float _MaskSpeedV;
|
||
#endif
|
||
#endif
|
||
|
||
#if _USEUVANI_ON
|
||
float _SpeedU;
|
||
float _SpeedV;
|
||
#endif
|
||
|
||
#if _USEUVDISTORTION_ON
|
||
sampler2D _UVNoiseTex;
|
||
fixed4 _UVNoiseTex_ST;
|
||
fixed _Distortion;
|
||
fixed4 _NoiseScroll;
|
||
#endif
|
||
|
||
#if _USEDISSOLVE_ON
|
||
sampler2D _DissolveTex;
|
||
fixed4 _DissolveTex_ST;
|
||
float _DissolveChannel;
|
||
fixed _Dissolve;
|
||
fixed _DissolveWidth;
|
||
#endif
|
||
|
||
// 通道选择:0=R 1=G 2=B 3=A。用点乘取通道,避免动态分量索引(SM2.0 不支持)
|
||
inline float UIMaskSampleChannel(sampler2D tex, float2 uv, float channel)
|
||
{
|
||
float4 c = tex2D(tex, uv);
|
||
float4 w = 1.0 - saturate(abs(channel - float4(0.0, 1.0, 2.0, 3.0)));
|
||
return dot(c, w);
|
||
}
|
||
|
||
#if _USEUIMASKCLIP_ON
|
||
fixed4 _ClipRect;
|
||
#endif
|
||
|
||
#if _USEVERTEXMASK_ON
|
||
fixed4 _VertexOffset;
|
||
fixed _VertexFlipX;
|
||
#endif
|
||
|
||
struct appdata_t {
|
||
float4 vertex : POSITION;
|
||
fixed4 color : COLOR;
|
||
fixed4 texcoord : TEXCOORD0;
|
||
UNITY_VERTEX_INPUT_INSTANCE_ID
|
||
};
|
||
|
||
struct v2f {
|
||
float4 vertex : SV_POSITION;
|
||
fixed4 color : COLOR;
|
||
fixed4 texcoord : TEXCOORD0;
|
||
|
||
#if _USEMASK_ON
|
||
fixed2 texcoordMask : TEXCOORD2;
|
||
#endif
|
||
|
||
#if _USEUVDISTORTION_ON
|
||
fixed2 texcoordNoise : TEXCOORD3;
|
||
#endif
|
||
|
||
#if _USEDISSOLVE_ON
|
||
fixed2 texcoordDissolve: TEXCOORD4;
|
||
#endif
|
||
|
||
#if _USEUIMASKCLIP_ON
|
||
fixed4 worldPosition : TEXCOORD5;
|
||
#endif
|
||
|
||
#if _USEVERTEXMASK_ON
|
||
fixed4 vertex2 : TEXCOORD7;
|
||
#endif
|
||
|
||
UNITY_VERTEX_OUTPUT_STEREO
|
||
};
|
||
|
||
fixed4 _MainTex_ST;
|
||
fixed _GlowScale;
|
||
fixed _AlphaScale;
|
||
|
||
v2f vert (appdata_t v)
|
||
{
|
||
v2f o;
|
||
UNITY_SETUP_INSTANCE_ID(v);
|
||
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
|
||
o.vertex = UnityObjectToClipPos(v.vertex);
|
||
o.color = v.color * _TintColor;
|
||
o.texcoord.xy = TRANSFORM_TEX(v.texcoord,_MainTex);
|
||
o.texcoord.zw = v.texcoord.zw;
|
||
|
||
#if _USEMASK_ON
|
||
o.texcoordMask = TRANSFORM_TEX(v.texcoord,_Mask);
|
||
#endif
|
||
|
||
#if _USEUVDISTORTION_ON
|
||
o.texcoordNoise = TRANSFORM_TEX(v.texcoord,_UVNoiseTex);
|
||
#endif
|
||
|
||
#if _USEDISSOLVE_ON
|
||
o.texcoordDissolve = TRANSFORM_TEX(v.texcoord,_DissolveTex);
|
||
#endif
|
||
|
||
#if _USEUIMASKCLIP_ON
|
||
o.worldPosition = mul(unity_ObjectToWorld, v.vertex);
|
||
#endif
|
||
|
||
#if _USEVERTEXMASK_ON
|
||
o.vertex2 = v.vertex;
|
||
#endif
|
||
|
||
return o;
|
||
}
|
||
|
||
fixed4 frag (v2f i) : SV_Target
|
||
{
|
||
#if _USEUVANI_ON
|
||
// 用 _Time.y(float)而不是 _Time.g(fixed):运行久了 fixed 精度不足会出现像素块/卡顿
|
||
i.texcoord.xy += _Time.y * float2(_SpeedU, _SpeedV);
|
||
#endif
|
||
|
||
#if _USEUVDISTORTION_ON
|
||
float2 noiseScrollXY = _NoiseScroll.xy;
|
||
i.texcoordNoise += fixed2(_Time.g * noiseScrollXY);
|
||
i.texcoord.xy += tex2D(_UVNoiseTex, i.texcoordNoise).xy*_Distortion*_NoiseScroll.zw;
|
||
#endif
|
||
|
||
fixed4 col = 2.0f * i.color * tex2D(_MainTex, i.texcoord.xy);
|
||
col.rgb *= _GlowScale;
|
||
col.a = saturate(col.a) * _AlphaScale;
|
||
|
||
#if _USEMASK_ON
|
||
#if _USEMASKUVANI_ON
|
||
i.texcoordMask += _Time.y * float2(_MaskSpeedU, _MaskSpeedV);
|
||
#endif
|
||
col.a = saturate(col.a * UIMaskSampleChannel(_Mask, i.texcoordMask, _MaskChannel));
|
||
#endif
|
||
|
||
#if _USEDISSOLVE_ON
|
||
fixed DissolveWithParticle =(_Dissolve*(1-i.texcoord.z)*(1+_DissolveWidth)-_DissolveWidth) ;
|
||
fixed dissolveMap = UIMaskSampleChannel(_DissolveTex, i.texcoordDissolve, _DissolveChannel);
|
||
fixed dissolveAlpha = saturate(smoothstep( DissolveWithParticle, (DissolveWithParticle+_DissolveWidth), dissolveMap));
|
||
col.a *= dissolveAlpha;
|
||
#endif
|
||
|
||
#if _USEUIMASKCLIP_ON
|
||
col.a *= UnityGet2DClipping(i.worldPosition.xy, _ClipRect);
|
||
#endif
|
||
|
||
#if _USEVERTEXMASK_ON
|
||
col.a *= smoothstep(1, 0, ((i.vertex2.x - _VertexOffset.x) * _VertexOffset.z + (i.vertex2.y - _VertexOffset.y) * _VertexOffset.w) * _VertexFlipX);
|
||
#endif
|
||
|
||
return col;
|
||
}
|
||
|
||
ENDCG
|
||
}
|
||
}
|
||
}
|
||
}
|