// TextScanEffect.shader // 文本扫光效果着色器,用于UI文本的动态扫光特效 // 功能:在文本上创建一个从左到右(或自定义角度)移动的扫光效果 // 优化:实现连续扫光,无间隔等待时间 Shader "Custom/TextScanEffect" { Properties { [PerRendererData] _MainTex ("Font Texture", 2D) = "white" {} [PerRendererData] _Color ("Text Color", Color) = (1,1,1,1) // 扫光参数 _ScanColor ("Scan Color", Color) = (1,0.8,0,1) // 扫光颜色 _ScanWidth ("Scan Width", Range(0, 0.5)) = 0.15 // 扫光宽度 _ScanSpeed ("Scan Speed", Range(0, 50)) = 1.5 // 扫光速度 _ScanIntensity ("Scan Intensity", Range(0, 5)) = 2 // 扫光强度 [HideInInspector] _ScanInterval ("Scan Interval", Range(0, 0.1)) = 0.0 // 隐藏间隔参数,默认为0实现连续扫光 _ScanAngle ("Scan Angle", Range(-45, 45)) = 30 // 扫光角度 // 添加遮罩所需属性 _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" } // 添加模板测试配置 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 { CGPROGRAM #pragma vertex vert #pragma fragment frag // 引入Unity UI所需的库 #include "UnityCG.cginc" #include "UnityUI.cginc" // 启用UI裁剪和Alpha裁剪功能 #pragma multi_compile_local _ UNITY_UI_CLIP_RECT #pragma multi_compile_local _ UNITY_UI_ALPHACLIP struct appdata_t { float4 vertex : POSITION; float2 uv : TEXCOORD0; fixed4 color : COLOR; }; struct v2f { float4 vertex : SV_POSITION; float2 uv : TEXCOORD0; float4 screenPos : TEXCOORD1; fixed4 color : COLOR; float4 worldPosition : TEXCOORD2; // 添加世界坐标用于遮罩裁剪 }; // 着色器属性声明 sampler2D _MainTex; // 字体纹理 fixed4 _Color; // 文本颜色 fixed4 _ScanColor; // 扫光颜色 float _ScanWidth; // 扫光宽度 float _ScanSpeed; // 扫光速度 float _ScanIntensity; // 扫光强度 float _ScanInterval; // 扫光间隔(已隐藏,保留变量以兼容旧版本) float _ScanAngle; // 扫光角度 // UI遮罩所需变量 float4 _ClipRect; // 裁剪矩形 // 顶点着色器 v2f vert (appdata_t v) { v2f o; // 转换顶点到裁剪空间 o.vertex = UnityObjectToClipPos(v.vertex); // 传递UV坐标 o.uv = v.uv; // 计算屏幕空间位置(用于扫光效果) o.screenPos = ComputeScreenPos(o.vertex); // 计算颜色 o.color = v.color * _Color; // 保存世界坐标用于UI遮罩裁剪 o.worldPosition = v.vertex; return o; } // 片段着色器 fixed4 frag (v2f i) : SV_Target { // 基础颜色计算 - 采样字体纹理并应用颜色 fixed4 tex = tex2D(_MainTex, i.uv); fixed4 col = i.color; // 应用字体纹理的alpha通道 col.a *= tex.a; // 屏幕空间计算 float2 screenUV = i.screenPos.xy / i.screenPos.w; // 扫光方向计算 float angle = radians(_ScanAngle); float2 dir = float2(cos(angle), sin(angle)); // 时间参数计算(实现真正连续的双重扫光) float speed = max(_ScanSpeed, 0.01); // 防止除零错误 // 计算三个错开的扫光时间,确保始终有扫光效果可见 float time1 = fmod(_Time.y * speed * 0.5, 3.0); // 第一个扫光时间 float time2 = fmod(_Time.y * speed * 0.5 + 1.0, 3.0); // 第二个扫光时间(错开1个单位) float time3 = fmod(_Time.y * speed * 0.5 + 2.0, 3.0); // 第二个扫光时间(错开1个单位) // 扫描带位置计算 float scanPos = dot(screenUV, dir); // 计算三个扫光的位置 // 扩大移动范围,确保扫光完全穿过屏幕 float lightPos1 = time1 - 1.0; // 从-1.5移动到1.5 float lightPos2 = time2 - 1.0; // 从-1.5移动到1.5 float lightPos3 = time3 - 1.0; // 从-1.5移动到1.5 // 计算三个扫光到当前像素的距离 float distance1 = abs(scanPos - lightPos1); float distance2 = abs(scanPos - lightPos2); float distance3 = abs(scanPos - lightPos3); // 计算三个扫光的强度 double width = max(_ScanWidth, 0.001); float scan1 = 1.0 - smoothstep(0, width, distance1); float scan2 = 1.0 - smoothstep(0, width, distance2); float scan3 = 1.0 - smoothstep(0, width, distance3); // 合并三个扫光效果(取最大值) float scan = max(max(scan1, scan2), scan3); // 将扫光效果叠加到原始颜色上 // 使用alpha值确保透明区域不会显示扫光效果 col.rgb += _ScanColor.rgb * scan * _ScanIntensity * col.a; // 应用UI遮罩裁剪 #ifdef UNITY_UI_CLIP_RECT col.a *= UnityGet2DClipping(i.worldPosition.xy, _ClipRect); #endif #ifdef UNITY_UI_ALPHACLIP clip(col.a - 0.001); #endif // 使用saturate确保颜色值在0-1范围内 return saturate(col); // 等同于clamp(col, 0, 1) } ENDCG } } }