Unity Shader实战:Logo流光扫光效果实现与优化
简介这套面向Unity游戏开发者的Shader流光效果工程针对Logo展示这类高频需求提供了纯Shader编码和流光贴图叠加两条实现路线。前者围绕ShaderLab语法通过表面函数、顶点与片元着色器、时间变量以及颜色Lerp/Blend混合来生成动态扫光后者则利用流光图片的UV偏移配合Repeat循环实现更直观的贴图滑动效果便于快速理解纹理动画机制。资源包仅92KB压缩包内共43个文件除核心的2个shader源码、2个mat材质与2张png贴图外还包含完整场景、ProjectSettings配置及Unity项目管理文件结构围绕walk_light场景组织导入即可运行和修改。该资源已有1422人学习属于轻量实用的Shader入门案例。学习时可通过对比两条实现路径掌握时间节点、纹理坐标变换、混合模式与属性面板参数控制等关键技巧同时Shader Graph中的Time和UV节点用法也有涉及方便后续在可视化编辑器中扩展出更多流光、描边或能量特效。1. 为什么静态 Logo 也要动Logo 流光效果背后的真实需求启动画面、活动页主视觉、数字孪生大屏页脚美术交付过来往往只有一张静态 PNG。想让界面显得高级最简单有效的做法不是逐帧动画而是在 Logo 表面加一条斜向高光带周期扫过。这就是 Unity Shader 里的 Logo 流光效果。它不是序列帧不依赖后处理 Bloom核心逻辑只有一段很短的 GPU 代码用 UV 坐标算出一个移动的高光权重再和原图叠加。相比在 C# 里每帧 SetPixel 去改贴图这种做法零 CPU 开销、无额外相机、不引入粒子系统特别适合不想为一个装饰光效搞出整套 VFX 方案的 TA 或程序。下面从原理到落地一步步拆代码可以直接抄。2. 先立住原理扫光是沿 UV 坐标移动的高光权重2.1 一维扫光公式是怎么推导的把 UV 想象成一张 0 到 1 的矩形画布Logo 贴图就铺在画布上。扫光的本质是在画布上找一个随时间移动的「高光区域」。这个区域在任何时刻都可以用一个一维位置t来描述扫光带是一条和 Y 方向平行、沿 X 方向移动的区域。位置随时间变化Unity 内置的_Time.y正好是已经累计的秒数。要让扫光循环而不是只跑一次就用frac取小数部分float t frac(_Time.y * _SweepSpeed);_SweepSpeed控制移动速度取小数部分后 t 会一直在 0 到 1 之间循环。这个 t 就是扫光中心线在 UV 坐标系里的 x 坐标。每个像素要算自己离这条中心线有多远横向距离是abs(uv.x - t)。离中心越远光带贡献越弱所以需要一个随距离衰减的权重函数。最直接的是把距离除以带宽_SweepWidth再用 saturate 夹到 0 到 1最后取反float falloff saturate(abs(uv.x - t) / _SweepWidth); float mask 1.0 - falloff;_SweepWidth越大分母越大falloff 增长越慢mask 衰减得就越慢光带越宽。这个 mask 的形状是硬边三角形直接用会出现明显的边界。给它加一个幂次就能把边缘收拢成柔和的渐变mask pow(mask, 4.0);pow 指数越大亮带中心越集中边缘越陡。指数为 1 时是线性斜坡视觉上像一个半透明的条指数 4 到 6 时视觉上更像一道高光扫过。这一段四行代码就是扫光 Shader 的主题骨架后面所有封装包括遮罩、角度旋转、软边、HDR 输出都是在这个 mask 上做文章。想先肉眼确认这个公式是否正确可以写一个最简调试 Shader直接把 mask 输出成颜色float4 frag(v2f i) : SV_Target { float t frac(_Time.y * 1.2); float d abs(i.uv.x - t); float mask pow(saturate(1.0 - d / 0.15), 4.0); return float4(mask.xxx, 1.0); }把这段放到任意一个 Unlit 材质上你会看到一条灰色亮带从左到右循环划过。如果这条亮带根本不移动检查_Time.y是不是被 Time.timeScale 设成了 0如果亮带宽度不对调分母里的 0.15 就行。2.2 用灰度可视化 UV动手前先看清方向做 Shader 最容易犯的错是不看 UV 直接写采样逻辑。Logo 贴图在 Atlas 里、在 Sprite 上、在 TMP 文字上的 UV 分布完全不同扫光方向对不对很多时候不是数学算错而是 UV 本身就不是你想象的样子。所以在我自己的流程里第一步永远是先把 UV 可视化出来。做法是拿一个临时 Shader把 uv 的 x 和 y 分别输出到 R 和 G 通道float4 frag(v2f i) : SV_Target { return float4(i.uv.x, i.uv.y, 0.0, 1.0); }在 Game 视图里看到的横纹渐变就是 u 方向竖纹渐变是 v 方向。左边是 0 还是右边是 0直接决定了扫光从哪个方向进。尤其是用了 SpriteAtlas 的 UI 小图它的 UV 不是 0 到 1 整段而是一个子图区域如果忘了看这一步后面调角度纯靠猜。这个测试 Shader 只做调试用写在一个单独 Pass 里验证完立刻删掉不要留在项目里污染变体收集。2.3 两种实现路径纯 Shader 还是 C# 驱动扫光的“移动”有两个驱动方式。第一种完全靠 Shader 内置的_Time.y。材质创建完拖上去就在动Art 同学在 Inspector 里改_SweepSpeed就能看到速度变化。好处是零脚本、零运行时开销适合展示型项目、程序化生成内容里的临时物件。坏处是扫光从哪一帧开始、速度怎么缓动、入场时要不要先扫一次这些都写死在 Shader 里后期想配合剧情节奏做调整只能改材质或改 Shader。第二种用 C# 脚本把参数传给 Material。这种做法把时间、速度、角度、颜色都暴露给上层逻辑美术可以在 Inspector 里调策划可以接动画曲线运营活动配置表也能驱动。代价是要处理材质实例化的问题否则不同物体共享材质时会互相污染。我的惯用策略是两套并存Shader 里所有流光参数统一命名C# 只做material.SetFloat不参与任何视觉计算。Shader 里没有外部传入参数时就使用默认值自动动起来脚本注入参数后 Shader 行为被覆盖。这样既能快速验证又能保证项目后期参数可控。3. 完整实现在 URP 下跑通一个 Logo 流光 Shader3.1 Shader 全代码与参数表把上面的核心公式扩展成可直接落地的 URP Shader需要加入旋转角度、遮罩、原图混合、HDR 颜色四块。这里给出一套我常用的版本使用 ShaderLab 加 HLSL适用于 Unity 的 URP 管线。Shader Custom/LogoLightSweeper { Properties { _MainTex (Logo主贴图, 2D) white {} _MaskTex (流光遮罩 (A通道), 2D) white {} _SweepColor (流光颜色, Color) (1, 1, 1, 1) _SweepSpeed (扫光速度, Range(-4, 4)) 1.2 _SweepWidth (扫光带宽, Range(0.01, 0.8)) 0.15 _SweepAngle (扫光角度, Range(-60, 60)) 30 _SweepIntensity (扫光强度, Range(0, 4)) 1.0 } SubShader { Tags { QueueTransparent RenderTypeTransparent RenderPipelineUniversalPipeline } Blend SrcAlpha OneMinusSrcAlpha ZWrite Off Pass { HLSLPROGRAM #pragma vertex vert #pragma fragment frag #include Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; CBUFFER_START(UnityPerMaterial) sampler2D _MainTex; sampler2D _MaskTex; float4 _MainTex_ST; float4 _SweepColor; float _SweepSpeed; float _SweepWidth; float _SweepAngle; float _SweepIntensity; CBUFFER_END v2f vert (appdata v) { v2f o (v2f)0; o.vertex TransformObjectToHClip(v.vertex.xyz); o.uv TRANSFORM_TEX(v.uv, _MainTex); return o; } float4 frag (v2f i) : SV_Target { float2 uv i.uv; // 以 UV 中心为原点旋转实现任意角度扫光 float angle radians(_SweepAngle); float2x2 rot float2x2(cos(angle), -sin(angle), sin(angle), cos(angle)); float2 rotUV mul(rot, uv - 0.5) 0.5; // 扫光位置t 在 0~1 范围循环 float t frac(_Time.y * _SweepSpeed 0.2); // 高光权重距离中心越近越亮pow 控制软边 float falloff saturate(abs(rotUV.x - t) / _SweepWidth); float mask 1.0 - falloff; mask pow(mask, 4.0); // 遮罩限制只让扫光出现在 Logo 笔画内部 float mainAlpha tex2D(_MainTex, uv).a; float sweepAlpha tex2D(_MaskTex, uv).a; float visibleMask max(mainAlpha, sweepAlpha); float4 mainColor tex2D(_MainTex, uv); // 在原图上叠加高光颜色支持 HDR 超出 1.0 float3 sweepColor _SweepColor.rgb * mask * _SweepIntensity; float3 finalColor mainColor.rgb sweepColor * visibleMask; return float4(finalColor, mainColor.a); } ENDHLSL } } Fallback Hidden/Universal Render Pipeline/FallbackError }顶点着色器里把物体空间顶点转裁剪空间同时用TRANSFORM_TEX处理 Tiling 和 Offset。注意TRANSFORM_TEX接收的是_MainTex_ST但如果 Mask 贴图和主贴图用了不同的 Tiling需要分开声明_MaskTex_ST并单独采样。片元着色器里第一件事是旋转 UV。扫光带默认是竖直的要让它是斜的就是把 UV 坐标整体旋转一个角度旋转中心放在 (0.5, 0.5)这样扫光绕贴图中心转动符合直觉。float2x2旋转矩阵里的正负号决定了顺逆时针角度给负值可反向。mask pow(mask, 4.0)这一行是关键。它把线性的三角权重变成更接近真实高光的窄带分布。指数改成 2 会更柔和改成 8 会像一条刀锋一样锐利这个指数就是软边控制参数。遮罩部分使用了max(mainAlpha, sweepAlpha)意思是主贴图已经是不透明的地方肯定能出现扫光如果额外给了 MaskTex可以在主贴图 Alpha 覆盖不到的区域补上限制。这样做的好处是不强制要求美术单独准备一张蒙版直接复用 Logo 本身的 Alpha 通道也能跑。最后输出颜色时mainColor.rgb保持原色sweepColor作为加色叠加。这样扫光带经过的地方会变亮不会把 Logo 本身颜色覆盖掉。_SweepColor和_SweepIntensity一起控制最终亮度颜色值建议在 HDR 模式下调高到 1.5 以上否则后面加 Bloom 时高光不够强。参数名作用常用范围默认_SweepSpeed扫光移动速度负数反向-2 到 21.2_SweepWidth扫光带总宽度0.02 到 0.30.15_SweepAngle扫光方向与水平夹角-60 到 6030_SweepIntensity高光叠加强度1 到 31.0_SweepColor高光颜色可设 HDR1.0 以上有效白色_MaskTex可选遮罩只取 A 通道无则用主 Alpha空白旋转 UV 时有一个容易被忽略的细节如果贴图宽高比不是 1:1旋转后扫光带会看起来被拉伸变宽视觉上像一个椭圆的斜边。修正方法是在旋转前把 UV 的 x 方向乘上贴图宽高比旋转完再乘回去这部分属于进阶调优看实际材质表现再决定要不要加。3.2 C# 驱动脚本参数联动纯 Shader 版本已经能跑但项目落地时通常还需要一个 C# 脚本暴露参数。下面是配合上面 Shader 的驱动脚本挂在挂载了 MeshRenderer 的物体上即可。using UnityEngine; [RequireComponent(typeof(Renderer))] public class LogoLightSweeperDriver : MonoBehaviour { [Range(-4f, 4f)] public float speed 1.2f; [Range(0.01f, 0.8f)] public float width 0.15f; [Range(-60f, 60f)] public float angle 30f; [ColorUsage(true, true)] public Color sweepColor new Color(1f, 1f, 1f, 1f); [Range(0f, 4f)] public float intensity 1.5f; private Material material; void Awake() { material GetComponentRenderer().material; } void Update() { if (material null) return; material.SetFloat(_SweepSpeed, speed); material.SetFloat(_SweepWidth, width); material.SetFloat(_SweepAngle, angle); material.SetColor(_SweepColor, sweepColor); material.SetFloat(_SweepIntensity, intensity); } }花点时间解释这段代码为什么这么写。GetComponentRenderer().material里的.material会返回一个材质实例而不是共享材质这意味着运行时每个物体拿到一份独立副本修改不会串到别的预制体。代价是实例化会增加一份材质内存但这个体量对 UI 和场景中少量 Logo 完全可以忽略。[ColorUsage(true, true)]允许彩色拾色器切换到 HDR 模式这里的 HDR 不是指 32 位浮点贴图而是让颜色值可以拖到 0 到 1 以上方便后续对接 Bloom。Update 里每帧调 SetFloat虽然开销不大但如果项目对性能极其敏感可以在 Start 里只设一次美术改参数时依赖 Inspector 的深化编辑就行。上面脚本保留了每帧更新是为了方便在运行模式里拖动滑杆实时看效果。3.3 材质设置与 3 个必调参数Shader 和脚本就位后实际使用遵循以下几步。创建一个新的 MaterialShader 选择 Custom/LogoLightSweeper把 Logo 主贴图拖到 Main Tex 槽位Alpha 通道保持完整如果 Logo 的 Alpha 覆盖不了笔画轮廓再准备一张白色蒙版放到 MaskTex 槽位。然后把带有 MeshRenderer 或 UI 组件的物体材质替换成这个新材质挂上驱动脚本运行即可看到效果。如果跑起来效果不明显优先调这三个参数_SweepWidth是最影响观感的参数。0.15 是一个相对均衡的起点想更锐利就压到 0.08 以下想更弥散就放到 0.25。这个参数和分辨率直接相关同样宽高比下 1080p 显得窄4K 下显得更窄建议按最终发布分辨率微调。_SweepAngle决定扫光带的走向。Logo 文字笔画偏纵向时30 度斜扫容易切到笔画之间形成断点笔画是横向排布时斜角扫出来更有质感。换角度时观察 sweeps 带是否贯穿文字主体的上下边界别让光带从文字空隙穿过。_SweepIntensity控制是否有「发光感」。1.0 以下只是轻微的提亮1.5 到 2.0 配合 HDR 颜色可以产生光晕超过 3.0 后大部分区域会过曝成纯白。实际项目中这个值很少超过 2.5除非你明确要做高调过曝风格。3.4 兼容性说明Built-in 管线和 Sprite 的注意如果项目还在用 Built-in Render Pipeline上面 URP 版本的 Shader 无法直接编译。需要把TransformObjectToHClip换成UnityObjectToClipPosinclude 换成UnityCG.cgincCBUFFER_START(UnityPerMaterial)可以直接去掉因为内置管线不强制 SRP Batcher。其余片元逻辑完全不用改。做到这一步你会发现Logo 流光 Shader 的核心并不依赖任何 URP 专属 API整个效果的成败集中在 UV 处理、权重数学、遮罩混合三块。这也是为什么它适合作为 Shader 入门到进阶的过渡案例的原因。4. 不是硬边白条软边、噪声扰动与发光质感4.1 软边的两种写法pow 与 smoothstep很多新手把扫光做出来后发现亮带边缘像一把硬尺子切出来完全不像光。原因是对 mask 只做了线性 clamp没有做边缘衰减。上面 Shader 里用的pow是一种软边写法指数越大中心权重保持越高边缘迅速收拢。另一种更符合图形直觉的写法是用smoothstepfloat distanceToCenter abs(rotUV.x - t); float mask 1.0 - smoothstep(0.0, _SweepWidth, distanceToCenter);这里的smoothstep在 0 到_SweepWidth范围内做 Hermite 插值边缘比单纯 saturate 平滑但对比 pow 少的是一点「高光锐度」。实际差异可以这样理解pow 版本亮带的中心区域更亮像一道汇聚的强光smoothstep 版本过渡更温和像一块柔光片扫过。两种写法都保留看风格需要切换。在做音游 Logo 或霓虹灯风格时我用 pow做品牌感强的企业 Logo 时用 smoothstep 更多。不管哪种软边都要注意带宽不能太小。像素级的锯齿经常不是抗锯齿没开而是_SweepWidth小到只有三个像素宽软边区域消失只剩硬切换。4.2 噪声扰动让扫光带出现颗粒感纯线性扫光干净但无聊。加入噪声扰动后扫光带会产生颗粒感、闪烁感或故障风效果适合游戏标题、电竞赛事氛围、数字孪生大屏里的科技感 Logo。关键是在 mask 上乘一个动态噪声值。用 Shader 里最经典的 hash 函数就行不需要采样噪声贴图float hash12(float2 p) { return frac(sin(dot(p, float2(127.1, 311.7))) * 43758.5453); } float noise hash12(rotUV * 10.0 _Time.y * 20.0); mask * lerp(1.0, noise, _NoiseIntensity);hash12接受一个二维坐标返回 0 到 1 的伪随机数。传入的坐标包含时间维度因此噪声会随时间翻滚。rotUV * 10.0控制噪声频率10 是每单位 UV 内有 10 个噪声特征乘得越大颗粒越细。_NoiseIntensity控制噪声混入程度0 等于关闭0.3 是一个比较微妙的起始值。需要注意的是噪声会让扫光带边缘出现碎点这些碎点叠加在透明区域上时同样需要被visibleMask限制。所以代码顺序是先算 mask再乘噪声最后才乘 visibleMask不要把乘法顺序写反。4.3 遮罩与主图 Alpha 的配合扫光带在空背景里直接画视觉上会穿帮。前面 Shader 里的visibleMask就是为了把扫光限制在 Logo 笔画内部。一个常见误解是把 mask 乘上主贴图的 alpha 就完事了。这在大部分时候可行但有两个坑。第一个坑是主贴图可能会带半透明的投影或者动效残留 alpha会让扫光在半个笔画的边缘亮度不均匀第二个坑是美术给的主贴图可能是方形底加透明但透明部分不是纯 0有残边扫光一叠残边就会发亮。稳妥做法是再准备一张纯黑底白字的 MaskTex把笔画精确画出来。着色器里用max(mainAlpha, sweepAlpha)组合两个来源哪个更保守用哪个避免透明残边穿帮。如果只需要快速验证可以让美术把主贴图的 Alpha 通道复制一份出来后面让美术直接导出带 alpha mask 的图即可。4.4 双面材质与透明队列在 URP 的注意在三维场景里Logo 可能贴在双面牌匾、旗帜、悬空广告牌上从背面看时 Shader 默认只渲染正面Logo 消失。不少新手以为是 Shader 写错了实际上只需要在 SubShader 里加一行Cull OffCull Off 会让片元着色器对正面背面都执行一遍。但如果模型是半透明的又开了 Cull Off两个面都会写入 alpha半透明叠加会显得很脏尤其是 UI 风格的薄片物体。这种情况更推荐的方案是保留 Cull Back再复制一个双面渲染的 Pass两 Pass 使用不同混合系数。透明队列里也有一条经验URP 默认使用物体距离排序超出一定距离后两个透明物体可能互相穿插。如果扫光 Logo 和另一个透明物体有重叠把 Logo 的Queue调成Transparent1强制它后绘制能消除大部分排序问题。这不是万能的复杂的重叠场景依然会暴露问题立牌类 Logo 我一般不用真半透明改用无 Alpha 的剪裁贴图更省心。5. 排查手册Logo 流光常见的 5 个翻车现场5.1 扫光整个不亮或者一片惨白现象Logo 上没有高光带移动或者是整块区域从暗到亮绵延不绝完全没有条带感。原因最直接的检查点是_SweepWidth。如果这个值设成 0.5 以上权重几乎在整张 UV 范围里都大于 0.3mask 摊平成一大片不会有扫光的感觉。另一个原因是_Time.y被 Time.timeScale 冻结扫光停在原地还有可能是_SweepSpeed设成了 0t 永远是一个定值。解决先把_SweepWidth压到 0.1 左右再看 Inspector 里的_SweepSpeed是否大于 0.1最后确认 Edit Project Settings Time Time Scale 没有被代码改成 0。这三步检查能在五分钟内排除 90% 的情况。5.2 扫光穿帮横穿文字而不是顺着字形走现象正方形贴图上有一道斜的白带划过白带经过透明背景时也亮Logo 笔画边缘出现一圈白边。原因没有乘遮罩或者把visibleMask用错了位置。直接在主贴图上叠加高光颜色透明区域虽然最终 alpha 是 0但颜色值已经被提亮混合后会在边缘产生亮边。解决保证高光项sweepColor在被加到mainColor.rgb之前乘上visibleMask。一个快速验证方法把主贴图 alpha 全部置 0看扫光带是否仍然可见如果还可见就说明遮罩没起作用。定位到 Shader 里的颜色相加行检查乘法顺序。5.3 扫光带边缘出现硬锯齿现象亮带边缘有像素级锯齿旋转角度后尤其明显像是一个多边形拖出来的边。原因_SweepWidth太小导致软边区域不到一个像素贴图分辨率低UV 离散化明显旋转矩阵没有做宽高比补偿导致斜向扫光被拉伸。解决把_SweepWidth提到 0.15 以上让边缘至少覆盖三到四个像素。同时把pow(mask, 4.0)改成smoothstep(0.0, _SweepWidth, distance)边缘会更自然地过渡。若有宽高比失真采样前先对 UV 做归一化处理float aspect _MainTex_TexelSize.w / _MainTex_TexelSize.z; float2 normalizedUV float2(uv.x * aspect, uv.y); // 对 normalizedUV 做旋转最后除以 aspect 还原5.4 在 URP 里把强度调到 10 也“不发光”现象_SweepIntensity已经调到 4颜色拉亮到 (3, 3, 3)屏幕上的结果还是纯白一片完全没有 Bloom 泛光。原因URP 里默认没有打开后处理的 Bloom。没有 Bloom 时任何超过 1.0 的颜色都会被直接钳制到纯白强度再高也只是白得刺眼不会有光晕扩散。Logo 流光本身没有自带泛光光晕来自后处理。解决在 URP Asset 里打开 HDR 支持创建 Volume 并添加 Bloom 覆盖阈值调到 1.0 附近强度 0.5 到 1.5 之间。这时_SweepColor的 HDR 值才发挥真正作用。UI 层的 Logo 如果跑在 Overlay Canvas 下注意 UI 不会进入后处理流水线需要把 Logo 放进单独的 Screen Space Camera 层才能吃到 Bloom。5.5 多个物体共用材质参数互相打架现象场景里十几个 Logo 挂同一个材质美术调整其中一个的 Inspector 参数其他 Logo 全部跟着变或者某个 Logo 运行时参数完全不生效。原因Renderer.material访问产生实例但实例在很多情况下仍然引用同一份MaterialPropertyBlock没有隔离。多个实例在编辑器里改了素材后共享的.mat文件被覆盖其他物体也读同一份数据。解决批量物体统一用MaterialPropertyBlock它能在不产生材质实例的前提下给每个 Renderer 设置独立参数。代码示意var block new MaterialPropertyBlock(); renderer.GetPropertyBlock(block); block.SetFloat(_SweepWidth, width); block.SetColor(_SweepColor, color); renderer.SetPropertyBlock(block);这样每帧更新时只改 PropertyBlock不产生额外材质内存也不污染共享材质。这是处理大量 UI Icon 或场景内多 Logo 最推荐的方式。6. 收尾用三步验证法把流光调到“高级感”前面写完了原理和代码最后说下验证习惯。我调这类 Shader 很少只靠肉眼在 Game 视图外看一帧画面而是固定用三步验证法。第一步Window Analysis Frame Debugger 打开逐帧找到包含这个 Logo 物体的 Draw Call。在 Draw Call 的详细信息里查看材质当前绑定的 Shader Pass、Blend 状态和 RenderTarget。如果这个 Draw 出现在 Opaque 队列里说明 Tag 写错了透明队列的 Logo 被当不透明处理混合表现全都不对。Frame Debugger 还能显示同一个 Draw 里 GPU 实际使用的属性快照比 Inspector 里的材质面板更接近真相。第二步做一个 UV 可视化开关。在 Shader 里加一个_DebugUV用#ifdef控制输出灰度 UV 图。确认当前贴图在 UI 上的 UV 范围、旋转方向、宽高比都符合预期。这一步能直接把扫光角度偏移的锅从「数学写错」里摘出去。很多扫光方向不对的问题最后都定位在 Atlas 子图 UV 没有归一化。第三步录一段正常速度的视频素材放到剪辑软件里逐帧检查。扫光的停留时间、带宽变化、过曝位置是否在可接受范围。肉眼容易忽略的闪烁和跳变在逐帧播放下一目了然。特别是加了噪声扰动后逐帧检查能看出噪声噪声频率是否过快导致扫光带明显抖动。另外想提一个常被忽略的场景如果你需要把流光效果做在 TextMeshPro 文字而不是贴图上直接套这个 Shader 一般行不通TMP 的 Mesh 和 UV 布局跟普通 Sprite 完全不同颜色混合也受 TMP 自己的材质结构控制。常见做法是把 TMP 文字渲染到一张 RenderTexture再用带扫光 Shader 的 RawImage 承载这张图或者改用 TMP 的 Shader 变体去加扫光逻辑。项目里遇到 TMP 场景我基本都是这样绕的。这套 Logo 流光方案我已经在 UI 活动页、数字孪生大屏 Logo 和前些年做 PICO 界面的时候用过几轮。技术上不算难坑都在细节里。先把基础版跑通再加噪声、软边、HDR Bloom一步一步来最后的效果会和商业竞品页面里的 Logo 光效在一个水平线上。希望帮到你。本文还有配套的精品资源点击获取