所有参数都支持在 Inspector 面板直接拖拽调节,无需改代码:
Properties
{
[MainTexture] _BaseMap("Base Map", 2D) = "white" {} // 主纹理(UI图片)
_Speed ("Sweep Speed", Float) = 2 // 扫光移动速度
_Width ("Band Width", Float) = 0.15 // 扫光光带宽度
_Brightness ("Brightness", Float) = 0.5 // 扫光亮度
_Skew ("Skew", Float) = -0.28 // 扫光倾斜角度(正负调整方向)
_ShimmerColor ("Shimmer Color", Color) = (1,1,1,1) // 扫光颜色
_Interval ("Pause Interval",Float) = 3.0 // 扫光循环暂停时间
_ShowUI ("Show UI 0:false 1:true",Float) = 0 // 显示模式:0=仅扫光 1=UI+扫光
}
SubShader 渲染设置(UI 专用配置)
这部分是UI 透明渲染的关键配置,保证扫光和 UI 正确叠加:
Tags { "Queue"="Transparent" "RenderType"="Transparent" "IgnoreProjector"="True" }
Blend SrcAlpha OneMinusSrcAlpha // 标准透明混合(正常UI透明模式)
ZWrite Off // 关闭深度写入(UI必须关闭,避免遮挡问题)
核心标签解释
Queue="Transparent":渲染队列设为透明队列,保证 UI 正常层级Blend SrcAlpha OneMinusSrcAlpha:Alpha 混合,让透明像素正确显示ZWrite Off:UI 控件不需要深度写入,关闭后避免特效闪烁 / 遮挡
1. 着色器声明 & 引用库
#pragma vertex vert // 声明顶点着色器
#pragma fragment frag // 声明片元着色器
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" // URP 核心库
✅ 必须引用 URP 核心库,否则坐标转换、纹理采样会报错。
2. 变量定义
float _Speed, _Width, _Brightness, _Skew, _Interval, _ShowUI;
half4 _ShimmerColor;
TEXTURE2D(_BaseMap); // 2D纹理声明
SAMPLER(sampler_BaseMap); // 纹理采样器
CBUFFER_START(UnityPerMaterial)
float4 _BaseMap_ST; // 纹理缩放偏移(TRANSFORM_TEX必需)
CBUFFER_END
_BaseMap_ST:Unity 自动生成的纹理参数,用于 UV 适配- CBUFFER:URP 规范写法,提升性能
3. 数据结构(Attributes & Varyings)
// 顶点输入:模型空间数据
struct Attributes
{
float4 positionOS : POSITION; // 物体空间顶点坐标
float2 uv : TEXCOORD0;// UV坐标
float4 color : COLOR; // UI顶点颜色
};
// 片元输入:裁剪空间数据(顶点输出→片元输入)
struct Varyings
{
float4 positionHCS : SV_POSITION; // 齐次裁剪空间坐标
float2 uv : TEXCOORD0; // 传递UV
float4 color : COLOR; // 传递顶点颜色
};
4. 顶点着色器 (vert)
作用:仅做坐标转换和数据传递,无复杂逻辑
Varyings vert(Attributes IN)
{
Varyings OUT;
// 物体坐标 → 裁剪空间坐标(Unity 标准转换)
OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
// UV 适配(处理贴图的平铺/偏移)
OUT.uv = TRANSFORM_TEX(IN.uv, _BaseMap);
// 传递UI颜色
OUT.color = IN.color;
return OUT;
}
5. 片元着色器 (frag) ------ 扫光核心逻辑
这是整个特效的灵魂,分5 步实现扫光效果:
步骤 1:采样原始纹理
half4 col = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, IN.uv) * IN.color;
- 采样 UI 贴图颜色,乘以顶点颜色(适配 UI 控件的颜色设置)
- Alpha 通道作为扫光蒙版:只有贴图不透明区域才会显示扫光
步骤 2:计算带暂停的扫光进度
float cycleDur = 1.0 / _Speed + _Interval; // 总周期=扫光时间+暂停时间
float t = fmod(_Time.y, cycleDur); // 取时间循环值
float progress = saturate(t * _Speed); // 0~1标准化进度
float center = progress * 1.4 - 0.2; // 光带中心位置(扩展范围,保证全屏扫过)
_Time.y:Unity 内置时间变量(随运行时间递增)saturate():限制数值在 0~1,防止越界- 核心效果:扫光移动 → 暂停 → 循环
步骤 3:UV 倾斜 + 计算光带距离
float u_skew = IN.uv.x + IN.uv.y * _Skew; // 倾斜UV(实现斜向扫光)
float d = abs(u_skew - center); // 计算当前像素到光带中心的距离
_Skew控制倾斜:正数 = 右上倾斜,负数 = 左上倾斜- 距离越小,像素越接近光带中心,亮度越高
步骤 4:计算扫光强度(柔边光带)
float shimmer = 1.0 - smoothstep(_Width * 0.3, _Width, d);
smoothstep(a,b,x):HLSL 内置函数,实现平滑过渡- 效果:光带中心最亮,边缘柔和过渡,没有硬锯齿
步骤 5:双模式渲染(仅扫光 / UI + 扫光)
if(_ShowUI <= 0)
{
// 模式0:仅显示扫光(隐藏原始UI,只留彩色扫光)
col.rgb = _ShimmerColor.rgb;
col.a = col.a * _Brightness * shimmer;
}
else
{
// 模式1:UI正常显示 + 扫光叠加(最常用)
half3 light = shimmer * _ShimmerColor.rgb * _Brightness;
col.rgb = lerp(col.rgb, col.rgb + light, col.a);
}
return col;
- 模式 0:适合纯特效(如技能高亮、提示光)
- 模式 1:UI 正常显示,扫光叠加在上方(如按钮高亮、图标特效)
完整代码:
bash
Shader "Custom/Shimmer"
{
Properties
{
[MainTexture] _BaseMap("Base Map", 2D) = "white" {} // 主纹理(UI图片)
_Speed ("Sweep Speed", Float) = 2 // 扫光移动速度
_Width ("Band Width", Float) = 0.15 // 扫光光带宽度
_Brightness ("Brightness", Float) = 0.5 // 扫光亮度
_Skew ("Skew", Float) = -0.28 // 扫光倾斜角度(正负调整方向)
_ShimmerColor ("Shimmer Color", Color) = (1,1,1,1) // 扫光颜色
_Interval ("Pause Interval",Float) = 3.0 // 扫光循环暂停时间
_ShowUI ("Show UI 0:false 1:true",Float) = 0 // 显示模式:0=仅扫光 1=UI+扫光
}
SubShader
{
Tags { "Queue"="Transparent" "RenderType"="Transparent" "IgnoreProjector"="True" }
Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off
Pass
{
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
float _Speed, _Width, _Brightness, _Skew, _Interval, _ShowUI;
half4 _ShimmerColor;
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
float4 color : COLOR;
};
struct Varyings
{
float4 positionHCS : SV_POSITION;
float2 uv : TEXCOORD0;
float4 color : COLOR;
};
TEXTURE2D(_BaseMap);
SAMPLER(sampler_BaseMap);
CBUFFER_START(UnityPerMaterial)
float4 _BaseMap_ST;
CBUFFER_END
Varyings vert(Attributes IN)
{
Varyings OUT;
OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
OUT.uv = TRANSFORM_TEX(IN.uv, _BaseMap);
OUT.color = IN.color;
return OUT;
}
half4 frag(Varyings IN) : SV_Target
{
// 采样贴图,仅使用其 Alpha(作为扫光蒙版)
half4 col = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, IN.uv) * IN.color;
// 带暂停的循环进度
float cycleDur = 1.0 / _Speed + _Interval;
float t = fmod(_Time.y, cycleDur);
float progress = saturate(t * _Speed);
float center = progress * 1.4 - 0.2;
// 倾斜 UV 并计算到光带中心的距离
float u_skew = IN.uv.x + IN.uv.y * _Skew;
float d = abs(u_skew - center);
// 扫光强度(带柔边)
float shimmer = 1.0 - smoothstep(_Width * 0.3, _Width, d);
if(_ShowUI <= 0)
{
col.rgb = _ShimmerColor.rgb;
// 扫光颜色:图的不透明像素 × 颜色亮度 x 强度
col.a = col.a * _Brightness * shimmer;
}else
{
// ── 颜色叠加(仅不透明处) ─────────────────
half3 light = shimmer * _ShimmerColor.rgb * _Brightness;
col.rgb = lerp(col.rgb, col.rgb + light, col.a);
}
return col;
}
ENDHLSL
}
}
}
效果展示:
