ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Unity Shader实现Logo流光效果:原理、完整代码与调参详解

Unity Shader实现Logo流光效果:原理、完整代码与调参详解 简介Unity Shader中的Logo流光效果是游戏界面、启动画面与品牌展示中常见的动态视觉特效适合具有一定Unity基础、希望借助ShaderLab或可视化Shader Graph自定义材质的开发者学习。这份zip压缩包共包含43个文件、约92KB内部有2个Shader源码、2个材质文件、20个Unity asset、1个场景文件以及PNG流光贴图、ProjectSettings配置和解决方案文件属于轻量级可直接运行的完整工程。资源提供了纯代码实现与流光图片叠加滑动两种思路覆盖Surface着色器、顶点片段着色器、UV坐标随时间偏移、Lerp/Blend颜色混合、Time变量驱动动画等核心知识点附带的Shader Graph相关说明也可帮助初学者从节点化角度理解同一效果。已有1422人学习下载对想快速掌握Logo流光效果并对照工程调试参数的开发者来说这一压缩包兼具参考与复用价值。1. 为什么 Logo 流光效果是 Unity Shader 入门的第一道坎运营周五下班前丢过来一句话给品牌 Logo 加个流光扫过的效果周一要。很多人的第一反应是去动画系统里找状态机折腾半天才发现这个效果根本不需要动画一个 Shader 就能让贴图自己动起来。Logo 流光效果是 Unity Shader 里最典型的 UV 滚动应用把一张高光贴图沿某个方向持续偏移再用遮罩把光限制在 Logo 的笔画范围内视觉上就是一道光反复扫过品牌字。它既是新手吃透 Vertex/Fragment 流程的第一个完整项目也是 UI 启动页、买量素材、3D 商品模型上低成本动态高光的常见做法。刚接触 ShaderLab 的 Unity 开发者能从这里拿到可复现的代码和调参清单做 UI 动效和广告素材的从业者也能快速判断这套方案的实现成本和边界。2. 流光效果的原理拆解UV 滚动、遮罩与混合模式2.1 所谓流光本质是让高光贴图沿 UV 方向移动先理清一个概念Logo 本身是静态的流光不是让 Logo 动而是让「光」在动。片元着色器里有两张贴图参与采样主贴图用原始 UV流光贴图用随时间偏移的 UV。偏移公式核心就一行float2 flowUV i.uv float2(1.0, 0.0) * _Time.y * _FlowSpeed; fixed4 flow tex2D(_FlowTex, flowUV);_Time.y 是 Unity 内置时间变量单位是秒Shader 里所有跟时间相关的动画都靠它驱动它实际是一个 float4y 分量是累计运行秒数。_FlowSpeed 是速度系数正数往右流动负数往左。把采样到的流光颜色叠加到主贴图颜色上视觉上就是一道光扫过去。这里的核心认知是主贴图采样永远用 i.uv只有流光贴图用带时间偏移的 flowUV两者一旦混用翻车方式会非常迷惑后面排查章专门讲。这里有个很多人第一次会踩的认知差流光贴图本身是一张带亮带的图UV 偏移方向直接决定光带走向。想要斜向扫方向向量别写死成 float2(1,0)用三角函数算float rad radians(_FlowAngle); float2 flowDir float2(cos(rad), sin(rad)); float2 flowUV i.uv * _FlowTiling flowDir * _Time.y * _FlowSpeed;角度 0 表示水平向右90 度表示沿 V 轴向上。注意 UV 空间的 V 方向和屏幕显示方向可能相反具体表现以你的贴图坐标为准这个反向问题在排查章会讲。_FlowTiling 是平铺系数大于 1 时一条流光会被压窄成多条小于 1 时光条更宽、更柔和。流光的观感还受贴图 WrapMode 影响Clamp 模式下光条从 UV 边界滑进滑出适合「一条光扫过去」Repeat 模式下贴图无缝平铺光条连续滚动适合「流水感」。做效果前先定这个后面调参会少走很多弯路。顺便说下为什么不用 Animator 去滚动 Offset 值动画方案不是不能做但每个对象都要挂状态机、要维护动画片段运行时还要逐帧改材质的 MainTexOffsetShader 方案是无状态的一个材质球全项目复用参数全收在属性面板里性能上也没有逐帧 CPU 开销。做大量 UI 物件复用时两者差距非常明显。2.2 遮罩决定了光只出现在 Logo 笔画里和辉光是两回事不加遮罩直接拿偏移后的流光颜色叠到主贴图上光条会扫过整个四边形区域连透明区域也跟着亮。对 Logo 这种不规则形状这个结果没法看。所以第二步是遮罩相乘col.rgb flow.rgb * mask;mask 是 0 到 1 的值笔画内是 1、笔画外是 0光只在 Logo 形状里显示。拿 mask 的常见做法有三种直接取主贴图 alpha 通道适合透明背景的 PNG单独做一张遮罩贴图适合形状和颜色要独立控制的场合对主贴图颜色做亮度判断但深色 Logo 容易漏笔画不推荐新手用。另外一个相关误区有人会去找 unity 反向遮罩组件来限制流光范围。UI 遮罩组件RectMask2D、Mask解决的是 UI 裁剪问题方向是「裁掉组件范围以外的内容」拿它限制流光等于把 Logo 也跟着裁掉方向完全相反。流光限制用 Shader 里的乘法一次就完成不需要引入组件。顺带澄清一个高频疑问Logo 流光和辉光不是一回事。有人搜 unity 辉光怎么做 post 吗——那是后处理方案对整帧画面高亮区域提亮再扩散走的是 Post Processing Volume 管线Logo 流光只作用于当前材质不需要后处理栈开销小得多。做 UI 动效选流光就行别把后处理堆进来后处理在 UI 渲染上还有兼容成本。2.3 混合模式怎么选加色混合还是正常透明混合Blend 指令决定这个物体的颜色跟背景怎么融合。做透明 Logo最常用Blend SrcAlpha OneMinusSrcAlpha也就是标准透明度混合主贴图 alpha 决定整体透明度适合 UI、启动页这类有背景色的场景光扫过去是「浮在表面上」的感觉。另一种是加色混合Blend One One适合深色或纯黑底上做表面发光质感暗处保持暗、亮处更亮像光从 Logo 内部透出来。但加色混合亮度会累计同一个位置叠多个透明物体会指数级过曝在移动端尤其要小心。选哪种取决于底图亮度底图是浅色就直接用正常混合底图是深色可以考虑加色。无论选哪种透明 Pass 都要配合ZWrite Off和Queue Transparent否则会出现遮挡关系错乱、半透明物体互相穿帮的玄学问题。这几个指令的搭配是透明 Shader 的基本功下面的完整代码里都带好了直接抄。3. 从零写一个 Logo 流光 Shader完整代码与五个必调参数3.1 完整 ShaderLab 代码从属性面板到片元着色器下面是一份可以直接放进的工程里用的完整 Shader内置管线下挂到材质球就能跑Shader Custom/LogoFlow { Properties { _MainTex (Logo 主贴图, 2D) white {} _FlowTex (流光贴图, 2D) white {} _MaskTex (遮罩贴图, 2D) white {} _FlowSpeed (流光速度, Range(-2.0, 2.0)) 0.6 _FlowAngle (流光角度, Range(0.0, 360.0)) 30.0 _FlowStrength (流光强度, Range(0.0, 2.0)) 1.0 _FlowTiling (流光平铺, Range(0.2, 2.0)) 1.0 } SubShader { Tags { QueueTransparent RenderTypeTransparent IgnoreProjectorTrue } Blend SrcAlpha OneMinusSrcAlpha ZWrite Off Cull Off Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include UnityCG.cginc sampler2D _MainTex; float4 _MainTex_ST; sampler2D _FlowTex; sampler2D _MaskTex; float _FlowSpeed; float _FlowAngle; float _FlowStrength; float _FlowTiling; struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; v2f vert (appdata v) { v2f o; o.vertex UnityObjectToClipPos(v.vertex); o.uv TRANSFORM_TEX(v.uv, _MainTex); return o; } fixed4 frag (v2f i) : SV_Target { fixed4 col tex2D(_MainTex, i.uv); // 遮罩 遮罩贴图R通道 × 主贴图Alpha二者同时限制 fixed mask tex2D(_MaskTex, i.uv).r * col.a; // 由角度计算流动方向结合时间做UV偏移 float rad radians(_FlowAngle); float2 flowDir float2(cos(rad), sin(rad)); float2 flowUV i.uv * _FlowTiling flowDir * _Time.y * _FlowSpeed; fixed4 flow tex2D(_FlowTex, flowUV); col.rgb flow.rgb * _FlowStrength * mask; return col; } ENDCG } } Fallback Off }逐段说明一下。Properties 里三张贴图加四个浮点参数其中 _MaskTex 默认是 white意味着不赋值就等于全白遮罩行为退化为只用主贴图 alpha。Tags 里的 Transparent 队列让 Unity 在渲染不透明物体之后再处理它Cull Off 保证 3D 物件背面也能看到流光这正好对应很多人搜的 unity 双面材质 shader 问题后面有专门排查。vert 阶段只做了一个 Transform 和 UV 传递TRANSFORM_TEX 会把材质面板上 Tiling/Offset 的调整应用到采样坐标所以如果你在材质面板调整了主贴图 Tiling流光遮罩的 UV 会保持一致。frag 阶段先取主贴图颜色再算 mask再算流动 UV 采样流光贴图最后把流光颜色叠加到主贴图上。注意 flow.rgb 没有乘自己的 alpha如果你的流光贴图是白条配透明底建议改成flow.rgb * flow.a否则透明区域残留的 RGB 会被加进画面这是后面要讲的灰边问题。3.2 五个必调参数速度、角度、强度、平铺、遮罩参数默认值作用调参建议_FlowSpeed0.6滚动速度负值反向UI 上 0.4~1.0 比较自然太快会闪成故障效果_FlowAngle30流光方向0 为水平左到右用 0右上扫光用 30~45视觉最舒服_FlowStrength1.0流光亮度叠加权重手机上 0.7~1.2超过 1.5 容易过曝丢失笔画_FlowTiling1.0光条疏密程度单条光用 1.0流水感用 1.5~2.0_MaskTexwhite遮罩贴图全白等于不限制换成黑白图后按笔画露出_FlowSpeed 的符号决定方向想要来回扫的效果可以在 C# 里用Mathf.PingPong(Time.time, 1f)去改材质属性不需要写第二个 Shader。_FlowAngle 超过 360 也可以Shader 里 cos/sin 会自动周期化所以这个参数几乎不可能调坏。_FlowTiling 容易被人忽略它的物理意义是流光贴图在 UV 空间里重复几次。调大之后光条变细变密适合「多道光依次扫过」调小之后光条变宽适合「一团光晕缓慢流过」。这个参数跟流光贴图本身的条宽要配合调贴图条已经很宽时就不要再把 Tiling 调大否则会出现明显的截断感。3.3 在 Unity 里接入UI 和 3D 物体的两套接法UI 上最省事的是用 RawImage 加材质创建 Canvas 下的 RawImage把材质拖到 Material 槽再把 Logo 的透明 PNG 赋给材质里的 _MainTex 即可。UGUI 的 Image 组件走 Sprite 流程自带顶点色和图集逻辑换自定义 Shader 后容易跟 Canvas 的图集采样打架所以能用 RawImage 就不用 Image。需要注意这个 Shader 没乘顶点色RawImage 上的 Color 调透明度不会生效想整体淡入淡出就去改 _FlowStrength 或者在 C# 里维护一个 _Color 属性不要指望组件上的 Color。3D 场景里常见做法是给模型本身换这个材质或者在 Logo 展示墙前放一个 Quad 贴上主贴图。模型的话记得 Cull Off 已经在代码里背面不会消失Quad 则要在材质面板确认 _MainTex 的 Tiling 跟 Quad 比例匹配否则 Logo 会被拉伸。如果做的是 PICO 这类 XR 项目里的立体展板把这个材质挂上去即可流光不会随着视角穿帮因为它是贴图空间的效果不依赖相机方向。接入后第一件事不是调参数而是确认三张贴图都赋值了主贴图是 Logo流光贴图是亮带遮罩贴图如果是白图就说明当前只用 alpha 裁剪。确认完再调方向不然很容易对着错误的效果白调半天。4. 流光纹理怎么做PS 渐变条与 C# 程序化生成两套方案4.1 用 Photoshop 三分钟做一张软边的斜向流光条没有现成流光贴图时最快是拿 PS 生成一张。新建 512×512 透明背景画布用矩形选框拉一条高约 64 到 96 像素的细长条填充白色然后滤镜里做 10 到 20 像素的高斯模糊让边缘完全软化CtrlT 把这条旋转到你想要的条带角度导出 PNG 时勾选透明。这样出来的贴图就是一条白色软边光带中间亮、两侧渐隐。这里有个容易被忽略的细节流光条必须软边不能是硬边。硬边条扫过 Logo 时边界会像一把刀切过去边缘锯齿和采样闪烁非常明显软边看起来才是「光扫过」而不是「白条路过」。如果想让光带带拖尾感可以把填充白色改成白到透明的线性渐变一头亮一头暗扫起来会有方向性。导出后导入 UnityTexture Type 选 Default勾选 Alpha Is TransparencyWrapMode 按需求选 Clamp 或 Repeat。如果是单条扫过效果Clamp 就够如果想做连续滚动必须 Repeat而且贴图左右边缘要能无缝衔接。判断方式很简单把图在 PS 里用偏移滤镜Filter Other Offset水平移半个画布看接缝处是不是一条明显的亮线是的话就把渐变条的起点和终点调成一致再导出。4.2 用 C# 在编辑器里程序化生成流光贴图团队里如果美术资源紧张可以在编辑器里用脚本直接生成效果可控还能批量出不同角度的版本。下面这段放到 Editor 文件夹下菜单栏会多一个 Tools/生成流光贴图using UnityEngine; using UnityEditor; public static class FlowTextureGenerator { [MenuItem(Tools/生成流光贴图)] public static void Generate() { Texture2D tex CreateDiagonalFlow(256, 256, 0.12f, 45f); byte[] png tex.EncodeToPNG(); string path Assets/Textures/FlowTex.png; System.IO.File.WriteAllBytes(path, png); AssetDatabase.ImportAsset(path); Debug.Log(已生成: path); } static Texture2D CreateDiagonalFlow(int width, int height, float barWidth, float angleDeg) { var tex new Texture2D(width, height, TextureFormat.RGBA32, false); tex.wrapMode TextureWrapMode.Clamp; // 垂直于流动方向的投影距离决定光条走向 float rad angleDeg * Mathf.Deg2Rad; Vector2 dir new Vector2(Mathf.Cos(rad), Mathf.Sin(rad)); for (int y 0; y height; y) { for (int x 0; x width; x) { float u (float)x / width; float v (float)y / height; // 投影到流动方向0.5 为中心barWidth 控制条宽 float d Vector2.Dot(new Vector2(u, v), dir); float a 1f - Mathf.SmoothStep(0f, barWidth, Mathf.Abs(d - 0.5f)); tex.SetPixel(x, y, new Color(1f, 1f, 1f, a)); } } tex.Apply(); return tex; } }这个生成器里的 angleDeg 指的是流动方向光条本身垂直于它。比如你让流光沿 45 度方向扫生成出来的条带就是另一条对角线方向的软边亮条扫起来正好是斜向掠过。barWidth 控制条宽0.12 大约是画布宽度的 12%窄一点更锐利宽一点更柔和实际效果可以在生成后再调整。用脚本生成的好处是参数全在代码里改完重新跑一次菜单就能换一批贴图不用反复在 PS 里调。注意生成函数里的 Mathf.SmoothStep 让边缘是平滑过渡而不是硬切这正好对应前面说的软边要求。生成完记得在导入面板确认 Alpha Is Transparency 和合适的压缩格式不然 PNG 的透明信息会被默认设置吃成灰边。4.3 尺寸、压缩格式与 WrapMode 的选型配合流光贴图本质上是一张低频渐变图不需要大分辨率。128 或 256 足够应付大多数 UI 场景只有产品级特写才需要 512。尺寸越大移动端带宽压力越大尤其在做 unity 游戏优化时这种看起来不占体积的渐变图往往是内存和带宽的黑洞。格式方面编辑器里 RGBA32 没问题但从 Shared 到真机发布建议在导入面板把 Format 压成 ASTC 或 CrunchedUI 场景如果不想牺牲透明质量至少把 Max Size 降到 256 并关掉 MipmapsUI 不需要 mipmap开了反而增加内存。3D 物件上的流光可以开 Mipmaps不然缩小看时会有摩尔纹。WrapMode 的选型跟效果强绑定Clamp 适合「扫过即走」的单次流光Repeat 适合「循环流水」。Repeat 贴图必须满足左右无缝否则每滚动一圈就有一个硬接缝闪一下这是最容易让效果显得廉价的原因。最后提醒一句流光贴图和遮罩贴图是两回事遮罩需要黑白分明流光需要软边渐变别用同一张图硬凑。5. 避坑与排查Logo 流光效果最常见的 5 个翻车现场这章是带项目时踩过的血泪经验每条都按现象、原因、解决的顺序写直接对照排查。5.1 流光不动或者主贴图自己滚起来了现象是调 _FlowSpeed 毫无反应或者更迷惑的是 Logo 主图自己在滑动位置都跑偏了。前一种的原因通常是速度参数被乘成了 0比如材质实例参数没传进去或者代码里把_FlowSpeed写成了别的变量后一种的原因是把 flowUV 错当成 i.uv 去采样 _MainTex等于让主贴图也参与了时间偏移。解决方法是先检查属性面板里参数是否真的不为 0再检查采样代码里主贴图用的一定是 i.uv只有流光贴图用 flowUV。最快的定位手段是临时把 return 改成fixed4(flowUV, 0, 1)看画面里颜色是否随时间变化变了就说明时间驱动没问题。5.2 遮罩失效整个方块都被照亮现象是光条扫过时包括透明背景在内的整个矩形都在发光像贴了一张亮纸。最常见的原因是 _MaskTex 没赋值默认 white 就是全 1遮罩等于没有另外是导入 PNG 时没勾 Alpha Is Transparency主贴图的 alpha 通道全部变成了 1乘出来的 mask 自然全白。还有一个隐蔽原因遮罩贴图的 UV 和主贴图不一致比如主贴图 Tiling 改过而遮罩没有两者错位后遮罩覆盖不到笔画区域。解决方法是先单独输出 mask 看一眼下一章有调试法确认笔画内是白、笔画外是黑再回头查导入设置和 UV 一致性。5.3 透明边缘出现黑边和灰边UI 上尤其明显现象是 Logo 边缘一圈发灰光扫到边缘时出现脏边。原因是 PNG 的半透明像素在导入时RGB 通道保留了原始颜色而不是按 alpha 压黑alpha 是 0 但 RGB 不是 0加色混合时这些残留 RGB 会被叠进画面。另一个来源是 mipmap 在采样边缘时混合了半透明像素。解决方法是导入时勾选 Alpha Is Transparency让半透明像素的 RGB 按 alpha 压黑如果压黑后仍有灰边把叠加公式改成col.rgb flow.rgb * flow.a * mask * _FlowStrength先用流光贴图自身的 alpha 过滤掉透明残留。这条在深色背景下尤其明显深色 UI 上做流光几乎必遇到。5.4 移动端帧率骤降透明物件一多就卡现象是编辑器里流畅真机上掉到 30 帧以下同一个界面叠了几个带流光的 Logo 就明显掉帧。原因有三个流光贴图用 1024 全尺寸且没压缩带宽被吃满透明物体层层叠加造成 overdraw同一个像素被反复执行片元着色器Shader 里的中间计算在低端 GPU 上走了全精度 float。解决方法是流光贴图压到 256 并开 Crunched 或 ASTC控制同一屏的透明层数带流光的 UI 不要叠超过两层把 flowUV 和 mask 相关的中间变量从 float 改成 half。透明混合的月光条是线性累计的叠三层以上亮度还会失真所以从设计上就该限制层数而不是事后调强度。5.5 3D 模型上背面发黑双面材质没生效现象是 Logo 做在 Billboard 或圆柱体表面从侧面或背面看是黑的旋转模型时光流消失在背面。原因是 Unity 默认 Cull Back背面被剔除很多人搜 unity 双面材质 shader 问的就是这个。加上 Cull Off 之后仍然发黑多半是模型法线反了背面朝向计算不对。解决方法是确认 SubShader 里写了 Cull Off本文的代码已经带上如果加了还黑去模型导入面板把 Normals 的翻转选项调整一次。纯 UI 平面不存在这个问题但只要挂到 3D 物件上Cull Off 几乎是必加项。6. 进阶双层流光叠加质感以及把中间变量输出到屏幕的调试法6.1 双层流光速度差与角度差才是质感的来源单条流光做出来往往像「白光条路过」廉价感明显。常见做法是叠两层一层宽而弱的底光负责氛围一层窄而强的亮光负责锐利扫过两层速度不同、方向略有偏移视觉上立刻丰富起来。改动只在片元着色器里加两次采样// 双层流光宽光打底窄光提亮 float2 uv1 i.uv * _FlowTiling flowDir * _Time.y * _FlowSpeed; float2 uv2 i.uv * _FlowTiling * 1.5 float2(-0.7, 0.3) * _Time.y * _FlowSpeed * 2.0; fixed4 flow1 tex2D(_FlowTex, uv1); fixed4 flow2 tex2D(_FlowTex, uv2); col.rgb (flow1.rgb * 0.5 flow2.rgb * 0.8) * mask * _FlowStrength;第二层用了更小的 Tiling 和更快的速度方向偏到左上两层叠加后光就有了层次。调参时记住一个原则底光的强度权重不要超过 0.6亮光控制在 0.8 到 1.0两层相加后如果超过 1.5笔画边缘就会过曝。这个参数组合也适合做「呼吸感」的循环流光比单层自然得多。6.2 调试习惯把遮罩和流光分别输出成画面调 Shader 最容易犯的错是把它当黑匣子对着最终画面盲调参数。实际上片元着色器里的任何中间变量都可以直接输出成颜色用画面验证。调试时把 return 临时换掉// return fixed4(mask, mask, mask, 1); // 只看遮罩黑白分明才正常 // return fixed4(flow.rgb, 1); // 只看流光条带软边才正常 return col; // 正常输出我现在的习惯是新写一个流光 Shader先单独验证遮罩再单独验证流光贴图最后才合到一起调参数。遮罩是黑白的、笔画边界清晰流光贴图是软边的、颜色过渡自然这两步确认完再调 _FlowAngle 和 _FlowSpeed基本不会走回头路。这个顺序帮我省掉了大量返工也推荐你在项目里把它当成固定流程。希望帮到你。本文还有配套的精品资源点击获取
返回列表