Unity的UI扫光效果Shader

所有参数都支持在 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必须关闭,避免遮挡问题)

核心标签解释

  1. Queue="Transparent":渲染队列设为透明队列,保证 UI 正常层级
  2. Blend SrcAlpha OneMinusSrcAlpha:Alpha 混合,让透明像素正确显示
  3. 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
        }
    }
}
效果展示:
相关推荐
skilllite作者2 小时前
UI-TARS-Desktop 智能桌面自动化实战指南
ui·自动化·策略模式
mxwin5 小时前
Unity Shader Alpha测试 · 模板测试 · 深度测试
unity·游戏引擎
梦想的颜色6 小时前
前端UI宝藏SKILL——UI/UX Pro Max
前端·ui·ux
2601_956002818 小时前
冬日狂想曲(赠去马赛克补丁)2026.5.13最新版免费下载 转存后自动更新 (看到请立即转存 资源随时失效)pc手机版通用
智能手机·游戏引擎·电脑·游戏程序·动画·游戏美术
Sator18 小时前
unity解决粒子与物体接触时的硬边缘问题
unity·游戏引擎
ZC跨境爬虫10 小时前
跟着MDN学HTML_day44:(ProcessingInstruction接口)
前端·javascript·ui·html·媒体
for_ever_love__10 小时前
UI学习:数据驱动ce l l
学习·ui·ios·objective-c
ZC跨境爬虫10 小时前
跟着MDN学HTML_day_45:(EventTarget接口)
前端·javascript·ui·html·媒体
RPGMZ11 小时前
RPGMZ NPC头顶自动显示一段消息
前端·游戏引擎·rpgmz·rpgmakermz