URP透明光晕Shader制作全流程:从贴图到Shader Graph动态特效
2026/9/16 21:06:27 网站建设 项目流程

URP项目里做透明光晕,说难不难,说简单也容易踩坑。很多人从内置管线迁过来之后,第一件事就是发现以前那套Shader不能用了,或者半透明效果一片死黑。我最近在处理一个技能特效的需求时,正好把整套流程从头到尾走了一遍——从一张普通的图片贴图,到最终在场景里飘起来带流动感的半透明光晕,中间踩了不少坑,也积累了一些相对顺手的做法。这篇文章就把这套流程完整拆开给你看。

这篇内容主要适合两类读者:一类是刚接触URP,想最快速度把带发光效果的透明材质做出来的新手;另一类是自己折腾Shader Graph已经有点感觉,但总觉得半透明混合、扭曲流动这些环节“差点意思”的人。我尽量避开那种“照着抄一个节点图就完事”的路线,把每一步为什么要这么做、参数怎么调、出了问题怎么排查都讲清楚。

1. URP下透明光晕的核心思路拆解

1.1 为什么URP里做透明光晕比内置管线“麻烦”

先说一个很多人刚迁到URP时的直接感受:内置管线里一套简单的Unlit Transparent Shader就能跑的透明材质,在URP里经常变成“透明变不透明”“发光变黑块”“半透明排序乱掉”这种让人头大的问题。

这里面的核心差异其实在于,URP把渲染路径做了统一封装,原来很多靠内置管线“默认行为”顶着用的写法不再生效了。特别是Shader里对混合模式、渲染队列、深度写入的处理,URP都需要显式地通过Surface Type、Blending Mode这些面板选项来控制。你要是沿用手写Shader的习惯直接往SubShader里塞Blend指令,很容易跟URP的SRP Batcher机制起冲突,结果就是材质在编辑器里看着正常,打包进真机就变了个样。

另一个麻烦点在于,URP对透明物体的光照处理跟内置管线的ForwardAdd完全不是一回事。光晕这种效果,本质上不依赖场景灯光,而是靠自发光(Emission)+屏幕后处理(Bloom)来呈现。但新手在URP里开了Emission之后发现,光晕效果并没有想象中的“亮起来”,反而灰蒙蒙的。这通常是因为颜色空间和HDR设置没有对齐。

所以在动手做之前,我强烈建议你先确认三件事:项目的Color Space是Linear还是Gamma,相机是否启用了HDR,以及场景里是否有挂Bloom的Volume组件。这三个条件缺一个,你做出来的光晕要么不发亮,要么亮得刺眼还泛白。

1.2 透明光晕的效果拆解:一张图需要拆成哪几个层次

我们把“光晕”这个词拆开看。一个看起来很“高级”的光晕,其实是由三个层叠的视觉元素构成的:

第一层是柔和的核心发光。这一层控制在贴图上就是中心最亮、边缘渐隐的径向渐变,通常是白色或浅色,配合HDR颜色输出,让它在Bloom作用下亮起来。

第二层是边缘扩散感。光晕如果只是圆圆的亮斑,看久了会很假。真实的光晕边缘会有细微的不规则感,可能是因为空气中的粒子、镜头的光学扩散,或者材质本身的纹理噪点。这一层通过叠加一张稍大的、透明度更低的渐变贴图,或者用噪声扭曲UV来模拟。

第三层是流动与动态变形。实时的光晕通常不是定格不动的,它会有轻微的脉动(呼吸感)、旋转、或者向某个方向拉伸。这一层靠顶点着色器做位移,或者在片段着色器里做扭曲采样来实现。

你手里拿到的“图片”,通常是一张带Alpha通道的普通贴图。我们需要通过Shader的光照模型、混合模式和UV动画,把它从“一张图”变成“一个有立体感、有动态的发光体”。

这跟你直接用Canvas里的Image显示贴图完全是两套逻辑。UI里的Image只是把图贴上去,没有光照、没有混合、没有后期交互;而我们要做的材质,是要放进场景、响应相机、配合后处理的,这决定了它的渲染设置和参数组合完全不一样。

1.3 为什么要用Shader而不是序列帧

做光晕这种效果,很多人的第一反应是“用AE或粒子系统导出序列帧,然后放到Unity里播放”。序列帧确实是万能的,但具体到“光晕”这种需求,用Shader来实时合成,在性能、包体控制、表现效果三个方面都更有优势。

序列帧的痛点是包体和内存。一张不错的512x512序列帧,30帧起步就已经很占空间了,而且在URP移动端上,UI和粒子系统的加载还会额外吃资源和内存。Shader方式只需要一张甚至两张贴图,配合算法去模拟动态,不管播放多久都只消耗固定的显存。

另一个关键点在自适应的灵活度。序列帧一旦生成,颜色、旋转速度、扭曲程度就都定死了,想微调只能回原软件改。而Shader方式里,这些全部是材质参数,字段拖一拖就完事了。策划说要“暗一点”“转得快一点”“边缘再虚一点”,都是几分钟的事情,不用重新出图。

当然,序列帧不是没用,角色大招那种非常复杂、多元素组合的特效,序列帧往往才是主方案。但单就“透明光晕”这种几何形状简单、动态规律明显的效果来说,实时Shader方案是性价比最高的选择。

2. 前期准备:贴图的处理与参数设置

2.1 贴图到底该用什么格式

有张好贴图,材质就成功了一半。但“好贴图”不是概念上的好看,它要满足几个跟透明光晕相关的技术要求。

首先是长宽比和分界线位置。光晕贴图通常采用正方形、中心点位于图片正中、图案向四周渐隐的布局。这样在Shader里做UV旋转、缩放的时候,旋转中心和贴图中心重合,不会出现绕圈偏心的现象。如果你拿到的贴图中心不在正中间,建议先在PS里调整画布,把有效图案居中,四周留出足够的透明边距。

其次是颜色通道的利用。大多数特效贴图把Alpha通道留出来做透明度,这没错。但对于光晕来说,RGB通道的亮度信息同样重要。推荐的做法是:RGB通道存的是图案本身的颜色亮度(高动态范围),Alpha通道存的是透明度遮罩。这样在Shader里,你可以分别控制“发光强度”和“透明度”这两件事。

这里有个很多人不知道的坑:当贴图被导入Unity并设为默认的Sprite(2D and UI)模式时,如果勾选了Generate Mip Maps,近大远小的场景里可能会出现边缘发暗或者闪烁。而当你把它用作特效材质时,通常需要关掉Mip Maps,或者至少在导入设置里把Wrap Mode设为Clamp,避免边缘采样出现接缝。

2.2 从PS到Unity:贴图导出与导入设置

在Photoshop里处理光晕贴图时,我通常走这样一个流程:

第一步,新建512x512或1024x1024的画布,背景设成纯黑。第二步,用径向渐变工具从中心向外拖一个白到黑的渐变,如果要做成“光圈”而不是“实心圆”,可以给渐变加一个“内发光”图层样式,或者用橡皮擦把中心擦出一点空隙。第三步,把边缘的透明度压到50%以下,让它在Bloom后处理里不至于整个糊成一个死白团。

这里有个细节需要特别注意:透明光晕在Shader里的基础混合方式是加法混合(Blend One One),这意味着透明通道其实不是必需品,RGB的亮度值本身就是发光强度的来源。所以你在PS里画贴图时,与其纠结Alpha通道干不干净,不如多花精力控制RGB的亮度曲线。中心最亮,往外线性衰减,这个衰减速率决定了光晕的软硬程度。

导出的图片格式,推荐PNG或者TGA,带Alpha,尽量不压缩。在Unity的导入设置里:

  • Texture Type选Default,不要选Sprite。
  • sRGB (Color Texture)保持勾选,如果要在Shader里手动做线性空间转换,再取消它。
  • Alpha Source选Input Texture Alpha
  • Alpha Is Transparency勾上,避免边缘出现白边。
  • Generate Mip Maps:如果是场景里的大光晕建议关掉,如果是远处小粒子可以打开,具体看使用场景。

2.3 材质面板的“URP定制”:Surface Type与Blending Mode

看到这里,你可能已经把贴图导入Unity了。接下来我们新建一个材质,默认情况下它出来的是一个Lit Shader的材质,完全不透明,看起来跟光晕没关系。这里不用慌,关键的操作在材质面板的顶部。

把Surface Type从Opaque改成Transparent,这一步直接决定了渲染队列从Geometry变成Transparent,材质才能混合进场景里。紧接着把Blending Mode改到Additive。Additive的意思是“叠加”,当贴图某个像素的RGB值是(0.5, 0, 0)这种暗红色时,它会直接把0.5加到背景像素上,导致该区域变亮,而不会把后面的物体盖住。

这就是光晕效果最核心的混合思路。跟普通的半透明“越叠越不透明”相比,Additive混合是越叠越亮。光晕周围的空气、光、微粒,本质上都是“往画面上加光”,用Additive是物理上说得通的。

Render Face在这个场景里建议改成Both,关闭背面剔除。光晕很多时候是面向相机的billboard形式存在,你希望从任意方向看它都是一个发光体,而不是从背面看直接消失。此外,勾选Depth Write要谨慎。Additive模式下如果开了深度写入,光晕背后如果有别的半透明物体,写入的深度值会跟渲染队列较劲,导致排序一片混乱。正常情况下保持不勾选就好。

3. URP的Shader配置:从内建到Shader Graph

3.1 为什么不直接写HLSL代码

在URP里写透明光晕的Shader,有两条路线:一条是手写HLSL,另一条是走Shader Graph的可视化节点。两条路各有利弊,我个人的习惯是:正式项目里用Shader Graph,科研型或者性能极致优化时才考虑手写HLSL。

Shader Graph最大的优势是门槛低、改起来直观。你不需要跟一堆GPU指令搏斗,只需要把节点连起来,参数全暴露在材质面板上,美术同学自己就能调。而且与URP的SRP Batcher兼容性极好,不用担心丢通道的问题。

但Shader Graph也有个坑需要注意:默认创建的Shader Graph节点图,如果使用Unlit Master节点,Emission通道默认是关闭加亮的。很多人在节点图里连了一堆Flowmap、Noise节点,最后发现输出依旧是灰的,就是因为没把Master节点的Emission强度拉上去。这一点我会在下面的实操里专门强调。

3.2 创建一个最简单的透明光晕Shader Graph

我们从头开始建一个最基础的版本。在Project窗口右键 -> Create -> Shader Graph -> URP -> Unlit Shader Graph,命名成GlowEffect_Additive

双击打开编辑器,主界面是Main Preview视口。先把Master节点右侧的Surface改成Transparent,Blend改成Additive,Render Face改成Both

接下来添加贴图。在左侧Create Node里搜索Sample Texture 2D节点,把2D参数配置成你导入的光晕贴图。连接方式:贴图 -> Sample Texture 2D的Texture端口;Sample Texture 2D的RGBA输出 -> Master节点的Emission端口。

这样已经能显示图像了,但你会发现它是黑色的,因为默认的Emission强度太低。在Master节点旁边找到Emission一栏,有一个强度字段。把它从1改成3或5。立刻就能看到画面亮了起来。

如果你这个时候在场景里挂一个带Bloom的Volume后处理,光晕周围就会有淡淡的泛光。Bloom在URP里的参数,我通常把Threshold设到0.9左右,Intensity调到2到3,这就够用了。Threshold太高会导致光晕不泛光,太低又会让全屏都亮起来,需要按项目实际效果反复试。

到这里,一个“能用”的光晕已经完成。但它还是死板的贴图。接下来才是重点。

3.3 加一点“灵魂”:UV扭曲、旋转与呼吸

静态光晕看两眼就想换掉了。我们来给它加三类动态:UV扭曲、整体旋转、透明度脉动。

UV扭曲的原理很简单:用一个噪声图(Noise Texture)来干扰UV采样的坐标,让原本规则的渐变边缘产生轻微的随机皱褶。在Shader Graph里,你新建一个Noise Sample 2D节点,选一个合适的噪声类型,比如Simple Noise。把它的输出乘以一个很小的强度值(0.02-0.05),再加到原始UV上。关键点在于这个强度不能大,否则贴图会被扯得面目全非。你可以在Noise Sample 2D上喂一个随时间变化旋转的UV,让噪声本身也在流动,这样光晕边缘就会像真实的火苗或者能量波动一样持续变化。

旋转怎么做?新建一个Rotate节点,把UV输入进去,Rotation端口接一个Time的Time节点乘以一个速度系数。我测下来,每秒旋转15度到45度之间看起来比较自然,太快就像涡旋,太慢几乎没有存在感。

脉动效果则简单得多,取一个Remap节点,把Time的正弦波结果从(-1,1)重映射到(0.8, 1.2),最后乘到最终输出颜色的Alpha或者Emission强度上。注意在Additive模式下,Alpha通道不参与混合,所以脉动效果应该作用在RGB上。做法是把脉动的缩放系数乘到Emission的强度通道上。

经过这么一套组合,光晕已经从“一张图”变成了“一个活着的效果”。

4. 更进一步的玩法:顶点动画与多纹理叠加

4.1 在Shader里做billboard朝向,而不是在脚本里转向

场景里的光晕,通常要求它始终面向相机。传统做法是让一个Quad始终LookAt主相机,但这要求每帧在C#里更新Transform,碰上批量特效用成百上千个光晕的时候,CPU开销就很肉疼了。

Shader里做billboard的通用做法,是在顶点着色器里把顶点坐标从模型空间变换到相机空间,然后利用相机的基向量来“摊平”Quad。具体到URP的Shader Graph里,有一个节点叫Transform节点,可以帮你把顶点从Object空间变换到View空间。再把View空间的顶点重新赋值给Vertex Position,配合Billboard节点,就可以让光晕在GPU上自动转向相机,完全不需要脚本参与。

或者更省事的方案:在Shder Graph中直接搜索“Billboard”节点。最新的URP版本提供了Billboard节点的快捷方式,你只需要把Object Space的顶点位置接进去,再配合Transform节点做空间转换,就能实现面向相机的效果。这个方案是做粒子光晕的标配,建议所有做特效的人都掌握。

4.2 两层贴图叠加,做出光晕的“厚度”

一张贴图做出来的光晕,总有一种“纸片感”,因为它的轮廓太过干净。一个常见的增强技巧是叠第二层贴图,用一张更大、透明度更低、稍微旋转过的贴图叠加在外围,形成一层像“光晕外围的散逸层”的东西。

在Shader Graph里,这就是两个Sample Texture 2D分支输出相加。注意相加之后的整体输出值可能会超过1(因为Additive混合本身就会叠加亮度),所以中间需要用Clamp节点处理一下,避免最终输出出现大量白色死区。

两张贴图的旋转速度和UV缩放最好设置成不同的值,这样叠加在一起,视觉上会有“内外圈转速不一致”的层次感,非常容易让人觉得这个光晕是3D的。你可以试试里圈旋转快一点,外圈旋转慢一点,或者反向转,效果会意外地好。

同理,透明光晕的“边缘发虚”也可以用这个技巧:外层贴图的主要作用是扩大Alpha的衰减范围,让整个物体的轮廓更柔和,暴力的边缘切割感被消解掉。很多看起来“贵”的特效,其实只是比别人多叠了一层贴图。

4.3 把微弱的方向感加进去:流动方向与拉伸

有些光晕是有方向性的,比如向上飘浮的能量、水平扩散的冲击波。这种效果不需要真的让模型动起来,往往只需要在UV上做个“单向偏移”。

在Shader Graph里,给UV坐标加一个向量,这个向量由Time驱动,比如(0, 1, 0)乘上Time再乘一个系数,意思就是纹理的采样坐标沿Y轴持续向上偏移。配合边缘渐隐的贴图,视觉上就产生了“能量从底部往上流动,到顶部消失”的效果。如果光晕要跟随角色移动方向做拉伸,就让顶点偏移的方向跟移动方向取一致,速度系数一般在0到2之间调整。

这里有个性能提醒:流动方向不应该做得太复杂。如果为了一个光晕写了大量的向量运算和分支判断,移动端GPU的Batch和指令开销会明显增加。光晕是辅助效果,不是主角,保持简单、可复用才是正路。

5. 最终检查与性能优化:从“能跑”到“能上线”

5.1 常见Bug排查:黑、灰、排序乱、闪烁

我把自己在实际调试中遇到最多的问题列成了一个清单,你可以对照排查:

  • 光晕是黑的:先检查材质面板的Emission强度或Shader Graph里Master节点的Emission强度,记住默认值往往不够,至少调到2以上。其次检查相机HDR是否启用,Bloom是否挂载,没有HDR和Bloom,光晕很难有“亮起来”的观感。
  • 光晕边缘有黑边或白边:贴图导入设置里把Alpha Is Transparency勾上,在材质面板里把Render Face设为Both,必要时把贴图的Wrap Mode改成Clamp,并用PS把贴图的边缘透明像素彻底清理干净。
  • 半透明排序乱掉:检查是否误开了Depth Write。Additive混合模式下别开Depth Write,另外把材质的Render Queue手动调到3500以上(在材质面板的Advanced Options里可以改)。如果多个半透明物体相互穿插,还是优先调整相机距离和物体位置,Shader层面很难完美解决。
  • 动态效果太快或太慢:Time速度系数没有调对。我习惯把Shader里的时间系数统一暴露成材质参数,这样不用每次进Shader Graph里改,直接材质面板拖动就行。
  • 真机上效果跟编辑器不一样:大概率是Color Space差异。URP推荐Linear+ HDR相机,建议先统一这个配置再对比。

5.2 性能基准:移动端能不能跑得动

透明光晕在移动端的性能,往往取决于两个点:Overdraw程度和Shader复杂度。

Overdraw很好理解,同一个像素被半透明物体反复绘制了多少次。光晕因为使用了Additive混合,它不会遮挡后面的物体,所以总是每帧都在重复绘制该区域的像素。当场景里光晕数量超过20个且互相重叠时,移动端GPU的填充率压力会立刻显现。优化思路是:用尽量小的网格(比如默认Quad甚至更小的面片)做光晕,别用Sphere或者Cylinder去做;同时控制光晕的堆积密度,特别是相机近处不要堆太多。

Shader复杂度方面,你如果用Shader Graph,尽量别加太多UV扭曲和非线性节点。移动端的GPU对于Texture Sample非常敏感,里外两层贴图+噪声采样,已经是比较吃带宽的配置了。如果再叠Flowmap或者Matcap,有可能会把中低端设备的帧率直接拖垮。建议按目标机型的最高档次来配置效果,但把低配参数预先做成材质开关,比如一个“性能模式”的Keyword,切换成单层贴图+无扭曲的简化版。

5.3 一个可以“抄作业”的参数预设模板

我把上文的完整参数整理成一个模板,你直接可以照抄:

  • 贴图:512x512,PNG带Alpha,图案居中、渐变柔和,最高亮度在中心。
  • 导入设置:Default类型,Alpha Is Transparency开启,Wrap Mode Clamp,Mip Maps关闭。
  • 材质设置:Surface为Transparent,Blend为Additive,Render Face为Both,Depth Write关闭。
  • Shader Graph Master:Emission强度3.0,Base Color留黑或白色,不重要。
  • UV扭曲强度:0.03,噪声Scale 8,旋转速度每秒20度,脉动范围为0.85到1.15。
  • Bloom后处理:Threshold 0.9,Intensity 2.5。

这套参数在大多数项目里都能出一个“及格以上”的光晕。之后再根据你的具体美术风格,把强度和速度做微调就行。

我个人在实际操作里还有一个习惯:每次做完一个光晕材质,就顺手用它做三个“变体”,一个最简单的单层版、一个标准双层版、一个带扭曲流动的高配版。这样真遇到性能和画面权衡的时候,直接换材质球就行,不用临时去Shader里翻。这也是我在项目里被磨过几次之后总结出来的经验,希望对你有用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询