做项目里那个悬浮传送门的时候,我一度被一个正方形的底色折磨到怀疑人生。魔法阵贴图明明只画了中间一圈符文,放到 quad 上一跑,四个角全部露馅:黑色方块底、边缘还有一条若有若无的亮边,怎么调光源和混合模式都压不下去。当时旁边路过的同事随口说了一句:你试试看 Shader Graph 右侧 Graph Inspector 里那个 Alpha Clipping。我勾上之后,方块当场消失,那一刻的心情你应该能想象。
后来我仔细把这件事从头到尾捋了一遍,才发现这个看似一秒钟就能解决的问题,背后牵扯到 alpha 通道、深度缓冲、渲染排序、边缘抗锯齿一堆东西。这篇文章就把整个思路写清楚,既告诉你为什么正方形底图会阴魂不散,也告诉你勾选 Alpha Clipping 之后还需要配哪些操作,以及它换来的新问题怎么处理。
1. 正方形底图的由来:quad 在忠实绘制每一个像素
1.1 quad 只会按部就班地画完整块矩形
很多刚接触 shader 的朋友会把“透明”理解为贴图自带的一种属性:这张 PNG 明明有透明区域,怎么到了场景里就变成方块了?这里的关键在于,纹理的 alpha 通道只是一份数据。Shader 拿到这份数据之后,如果不做任何针对 alpha 的处理,它就会以完全不透明的状态把整张 quad 覆盖的每一寸像素都写进颜色缓冲。
quad 是矩形,所以最终显示出来的是什么?矩形。圆形符文只是矩形里面的一块颜色信息,矩形本身依然存在。传送门特效常见的做法是把一张魔法阵贴图放到 quad 或者 plane 上,或者直接在 shader 里程序化生成图案。无论是哪种,只要 shader 走的是最普通的 Opaque 渲染路径,那么 quad 四个角上那些“没有东西”的像素也会被赋予颜色。如果贴图四个角恰好是黑色,这个黑色就会作为背景留下来。
这个现象之所以特别容易被误解成“贴图问题”,是因为我们在图像处理软件里看 PNG 时,透明区域会用灰白棋盘格显示,看起来好像“已经被处理过了”。但游戏引擎的渲染管线和图片编辑器是两码事。图片编辑器里的透明信息存储在 alpha 通道里,它存在,但 GPU 默认不会主动用它做什么。你必须在 shader 里显式告诉 GPU:把 alpha 值低于某个标准的像素扔掉,或者用 alpha 去和背景做混合。否则它就是一个普通的矩形纹理,像素一个不少地全部画出来。
1.2 改用 Transparent 之后,方块只是“看起来没了”
遇到这种情况,第一反应通常是去把 Surface Type 从 Opaque 改成 Transparent。改完之后确实能看到方形消失,因为 alpha 为 0 的角落开始与背景颜色混合了,视觉上背景透了过来。但这个操作有一个很大的隐患:透明混合意味着这些像素仍然被渲染了,只是颜色按 alpha 权重和背后场景做了混合,它们依然在消耗填充率,也会对后续所有依赖透明排序的功能造成影响。
做过一段时间 Unity 的人几乎都被半透明排序坑过:两个玻璃面重叠会闪烁、透过传送门看不到后面的角色、Bloom 一开整个方块都跟着发光。这些现象本质上都源自同一个事实——你的 shader 是在“假装看不见”那些像素,而不是真的把它们扔掉。混合模式只是改变了颜色的合成方式,像素该走片元着色器还是走,该占的带宽还是占。
还有更隐蔽的一层:Transparent 默认不写入深度。这意味着传送门后面如果站了一个不透明角色,两者的遮挡关系要靠渲染顺序来猜。顺序猜对了没事,猜错了就会出现角色明明站在门后面却被门挡住、或者角色在门前却被门洞穿帮的诡异画面。你花一晚上去调 Sorting Order、调 Render Queue,最后发现治标不治本,因为问题的根源是像素没有被真正移除。
1.3 勾选 Alpha Clipping:GPU 把像素直接丢弃
Alpha Clipping 做的事情和透明混合完全不同。它在片元着色器的最末端加了一条分支指令:当片元的 alpha 值小于你在面板上设定的阈值时,这个片元会被直接丢弃,不写入颜色缓冲,不参与任何混合,也不写入深度。你可以把它想成一把剪刀,沿着 alpha 遮罩的轮廓把渲染结果剪成你想要的形状。
在 Shader Graph 里勾选这个选项,最终生成的 shader 里大致等价于一句:
clip(i.alpha - _AlphaClipThreshold);学过一点代码的人看到这里应该就明白了:阈值 0.5 就是把 alpha 对半劈开,小于一半的像素当场剔除。这个操作放在 Opaque 渲染管线上,让一个本来完全正方形的 quad 在渲染时变成实际图案的形状。方形底图的问题,从根源上消失了,而不是被“混合”掉了。
下面这张表可以很直观地看出两者的本质差异:
| 维度 | 透明混合 Transparent Blend | Alpha Clipping 像素裁剪 |
|---|---|---|
| 底层原理 | 像素参与 Blend,和背景颜色合成 | 像素被 discard,直接不存在 |
| 方形底图 | 视觉上透明,但边缘有残留渐变 | 像素被丢弃,方形彻底消失 |
| 深度缓冲 | 默认不写入,排序容易翻车 | 正常写入,遮挡关系稳定 |
| 渲染排序 | 依赖 Sorting Order,重叠闪烁 | 作为不透明物体处理,稳定 |
| 边缘观感 | 半透明渐变自然 | 硬边,需要用噪声等手法缓解 |
| GPU 开销 | 半透明填充开销大 | 有 discard 分支开销,通常可控 |
2. Graph Inspector 操作细则:开关位置、配套设置与组合拳
2.1 开关不在普通 Inspector 面板里
先说最容易踩的坑。很多人听到“勾选 Alpha Clipping”,第一反应是去 Unity 主界面的 Inspector 面板找——选中材质球,唰唰唰翻了半天,属性列表里根本没有这个选项。这是因为 Alpha Clipping 是 Shader 图层的配置,不是材质数据,它必须在 Shader Graph 编辑器窗口的 Graph Inspector 里改。
正确路径是这样:双击 shader 资产打开 Shader Graph 编辑窗口,在窗口右上角找到 Graph Inspector 按钮,按一下展开右侧面板。如果找不到,也可以从菜单栏调出。面板里找到 Graph Settings 区块,展开 Surface Options,Surface Type 下面就是 Alpha Clipping 勾选框。不同版本的 Unity 和不同渲染管线里位置可能略有偏移,但大方向是一致的。
普通 Inspector 面板上你只能看到材质参数,比如你在 Shader Graph 里显式暴露出来的 Color、Float 这些属性。而 Alpha Clipping 属于引擎级配置,不在材质参数列表里,所以永远不要指望在 Material Inspector 中找到它。这个遗忘成本挺高的,我当初对着材质面板找了半小时,还一度怀疑是自己的 Shader Graph 版本太低,没有这个功能。
2.2 勾选之后,必须把 alpha 输出接到 Fragment 端口
勾上 Alpha Clipping 只是给 shader 加上了“丢弃像素”的权限。但如果此时 Master Stack 的 Alpha 端口空着,默认的 alpha 值是 1,阈值默认 0.5,alpha=1 永远大于 0.5,所有像素都会被保留——你勾了半天,方块还在。
正确的顺序是:先确认 Fragment 阶段的 Alpha 端口有值。最简单的方式,把你想用来裁剪的遮罩图,一般就是主纹理自带的 alpha 通道,或者一张黑白图,连到 Alpha。连完之后会立刻看到 quad 上遮罩为黑的部分全部消失;如果图案反了,中间连一个 One Minus 把 alpha 翻转过来。我习惯在连之前先用一个 Color 节点临时给 Alpha 接 0.5 测试一下,确认开关真的生效了,再换上正式遮罩。
如果连了 Alpha 却发现画面整体消失,别慌,检查一下是不是 Alpha 的值全为 0,比如误把一张纯黑纹理拖进去了。还有一种情况是贴图的导入设置让 alpha 数据在压缩时丢失,图片在预览时看着有透明区域,但 GPU 读到的 alpha 是 1 或者 0。遇到这种问题,去贴图导入面板里检查 Alpha Source、Alpha Is Transparency 这些选项,必要时关掉压缩重试。
2.3 Surface Type 建议留在 Opaque,Render Face 记得开 Both
强烈建议 Surface Type 保持 Opaque,不要为了“软边”改成 Transparent。传送门这种特效本质上是一块自发光薄片,使用 Opaque 配合 Alpha Clipping 能获得最稳定的深度排序和遮挡表现;一旦切到 Transparent,你就回到了上一章说的排序地狱,等于把更稳定方案拱手让给老问题。很多教程为了演示渐变效果会默认用 Transparent,但实际项目里,Opaque 加 Clipping 才更接近生产力选择。
Render Face 这个选项容易被忽略,但它直接影响传送门的体验:如果你只保留默认的 Front,玩家绕到传送门背面时会发现圆环消失,只剩下一个被剪掉形状的洞。传送门圆环是两面都要可见的物件,所以在 Surface Options 里把 Render Face 设为 Both。做完这一步,传送门从哪边看都有完整的环。配合前面说的不透明排序,一个双面裁剪的传送门门框就立住了。
这里再补充一点:如果用的是 Lit Shader Graph,传送门表面可能会受场景光照影响,暗处会显得灰蒙蒙。传送门特效绝大多数是自发光,建议直接用 Unlit 或者把材质里的 Emission 拉高,Base Color 压黑,让光完全由发光通道贡献。这是我做了几个特效之后才总结出来的,用 Lit 又不开光照,剪裁完的门环又黑又脏。
3. 程序化传送门圆环的节点装配:从 UV 到动态环带
3.1 用 UV 造一个距离场
上面聊的都是直接用贴图 alpha 裁剪,是标题里最直接的解法。但如果手上没有现成的透明贴图,也可以在 Shader Graph 里程序化生成传送门圆环的 alpha,下面把这套节点思路也分享一下。
思路不复杂:把 UV 坐标的中心挪到 quad 的中心,然后用 Distance 节点算出每个像素到中心的距离。这个距离就是一张径向渐变:中心是 0,边缘大概是 0.707,取决于你 quad 的纵横比。有了这个距离场,就可以用半径参数控制镂空范围。在 Shader Graph 里做的话,UV 节点输出后先接一个 Subtract 节点,减去 (0.5, 0.5),再接到 Distance 节点,Distance 的第二个输入给一个 Vector2 的零点即可。
如果想要传送门不是正圆而是椭圆,可以在距离计算之前把 UV 的 x 或 y 单独做 Scale。更花哨一点,用 Rotate 节点旋转 UV,让环上某些符文跟着转动。距离场的核心优势在于它天然是连续渐变,后续接 Smoothstep 做边缘羽化非常顺手。相比直接画贴图,这种程序化方式的参数化程度高,改半径、改环宽、改羽化宽度都是拖滑条的事。
3.2 两个 Smoothstep 拼出环形
环形等于内圈遮罩乘以外圈遮罩。外圈遮罩让半径超过外圈的部分变 0,可以写成 1 减去一个 Smoothstep;内圈遮罩让半径小于内圈的部分变 0,直接用一个 Smoothstep。两者相乘,得到只存在于内圈和外圈之间的环带。
在节点图里具体操作:外圈遮罩用一个 Smoothstep 节点,In 端口接入距离 r,Edge1 和 Edge2 分别设为 outer 和 outer 减去边缘宽度,再用 One Minus 翻转。内圈遮罩用另一个 Smoothstep 节点,In 同样接 r,Edge1 和 Edge2 分别设为 inner 减去边缘宽度和 inner。两个结果用 Multiply 相乘,输出到 Fragment 的 Alpha 端口。这个边缘宽度我习惯控制在 0.02 到 0.05 之间,太小的话裁剪阈值一卡,边缘只有一两个像素的过渡,锯齿非常明显;太大则整个门环看起来雾蒙蒙的,能量感大打折扣。
需要提醒的是 Smoothstep 的 Edge 输入不要设置成相等的值,否则计算结果是硬跳变而不是过渡,会得到一个特别生硬的边界。如果你想要的是那种刀切一样的硬边传送门,那无所谓,但通常做特效都想保留一点羽化量,哪怕最后被 Alpha Clipping 阈值砍掉大半,保留下来的一点点渐变也会让边缘不那么干涩。
3.3 噪声扰动:让边缘流动起来
纯数学圆环太规整,看起来像 UI 图标被丢进了 3D 场景,缺乏“能量场”的感觉。要让传送门有流动感,得在距离场上做文章:采样一张噪声贴图,或者用 Gradient Noise 节点,把噪声值乘以一个很小的强度,加到距离 r 上,再送进 Smoothstep。由于噪声场在空间上不连续,传送门边缘就变成了不规则、流动的形态。
具体做法:Gradient Noise 节点输出一个 0 到 1 的值,先用 Multiply 乘一个强度系数,比如 0.02 到 0.05,再和距离 r 做 Add,最后接 Smoothstep。用 Time 节点驱动噪声贴图的 Tiling And Offset,让噪声朝某个方向滚动,传送门边缘就像被风吹动的能量旋涡。强度从 0.01 开始往上加,调到边缘看得到扭曲、但门洞还能认出是圆形为止。
这里还有一个附加福利:带噪声扰动之后的 alpha 不再是一整片光滑渐变,clip 阈值在噪声场的起伏处会形成很不规则的边界,天然具备类似手绘边缘的质感,反而比纯 Smoothstep 更抗锯齿。我很推荐在做传送门、法阵、结界这类特效时都用这套“距离场加噪声扰动”的组合,因为它能同时解决形态自然度和边缘生硬两个问题。
3.4 Emission 与 HDR 颜色:别把亮度混进 Alpha
传送门要靠 Bloom 或者自发光来体现能量质感。在 Shader Graph 里,把 Fragment 的 Base Color 连成接近黑色,Emission 接上 HDR 颜色节点,再用 Float 去乘强度。多尝试强度大于 1 的颜色值,比如一个 (2, 6, 12) 的蓝色,Bloom 才能吃得开。如果颜色强度全是 0 到 1 的范围,Bloom 基本没什么反应,这是很多特效看起来“不够亮”的直接原因。
特别强调:alpha 只负责裁剪,不负责亮度。很多人觉得传送门不够亮,顺手把 Emission 亮度接进 Alpha,结果稍微一调,门中间先被抠空了。正确的做法是亮度走 RGB,形状走 Alpha,两条线各司其职,不要混用。传送门中心那团能量如果要更亮,就在 Emission 上乘一个更大的值;而 alpha 只决定哪些像素存活、哪些像素被丢弃。这两件事在 shader 里是完全独立的,混在一起只会让调试变得非常痛苦。
4. 阈值调节、边缘质量与半透明之间的三难选择
4.1 Alpha Clip Threshold 的甜蜜点
勾选了 Alpha Clipping 之后,Surface Options 里会出现一个 Alpha Clip Threshold 滑块。这个值的物理含义很直接:alpha 低于它的像素全部被丢弃,高于它的像素被保留。它不是透明度,而是“生死线”。
我的调试习惯是这样的:先把 Threshold 拉到 0,这时所有像素都会被保留,方形底图完整可见,但你能看清楚自己到底有哪些残留;然后缓慢往上调,调到方形底图刚好消失的位置,这就是当时的“最低有效阈值”。这个位置往往就是甜蜜点——它能在去掉底图的同时保留尽量多的 alpha 渐变过渡,让传送门边缘看起来更柔和。
按经验给一个参考区间:
| 阈值区间 | 画面表现 | 适用场景 |
|---|---|---|
| 0.0 ~ 0.1 | 底图残留明显,基本没裁剪 | 排查问题用,或 alpha 本身已经是硬黑白 |
| 0.1 ~ 0.25 | 方形消失,边缘保留渐变 | 想要柔和边缘、带雾气感的传送门 |
| 0.25 ~ 0.35 | 平衡点,边缘半硬半软 | 大多数传送门、法阵、结界 |
| 0.35 ~ 0.5 | 边缘锐利,类似硬切 | 强调轮廓清晰,能接受边缘锯齿 |
| 0.5 以上 | 大量细节被裁剪,可能破洞 | 特殊风格化需求,一般不建议 |
如果遮罩图本身是黑白分明的硬边贴图,阈值怎么调差异都不大;如果 alpha 经过了 Smoothstep 或噪声扰动,阈值调节才会明显改变观感。这套方法不仅适用于传送门,任何“只要图形、不要底图”的 shader 都能用同样的思路定位阈值。
4.2 边缘锯齿与移动端平台差异
Alpha Clipping 是硬裁剪,像素要么存在要么不存在,因此最终边缘只有一到两个像素的过渡带。在 1080P 以上的屏幕上看,问题不大;到了手机这种像素密度和分辨率参差不齐的环境,锯齿和闪烁就非常明显。更要命的是 MSAA 对已经丢弃的像素没有任何帮助,边缘依然会呈现阶梯状。
缓解手段我按效果排序:第一是加宽 Smoothstep 的过渡带,让裁剪线在多个像素之间渐变,而不是一个像素瞬间翻转;第二是加噪声扰动,让边缘形态不规则,视觉上打破锯齿的规律感;第三是依赖后处理抗锯齿,比如 SMAA、FXAA、TAA,它们对 alpha test 生成的边缘有效。还有一个小细节,贴图的 mipmap 会在降采样时把 alpha 边缘变成灰色,导致远处裁剪边缘不断闪烁收缩,处理方法是贴图导入设置里正确配置 alpha 相关的 mipmap 选项。
移动端 GPU 还得考虑另一种风险:大量使用 discard 会打断一些硬件优化路径。在基于瓦片的移动 GPU 架构上,被丢弃的像素虽然不写入颜色缓冲,但片元着色器的工作量并没有减少多少。场景中传送门只是个位数对象时完全不用担心;但如果全屏粒子、草地、传送门都在疯狂 discard,帧率可能被拖垮。遇到这种情况,优先减少透明物体的数量级,把硬裁剪留给最重要的几个物件。
4.3 半透明与排序的真正取舍
Opaque 配合 Alpha Clipping 天生不支持真正的半透明混合,它只能给出“在”或者“不在”的二值结果。如果传送门边缘想要那种拖曳的火焰质感,或者门洞周围要有一层半透明的能量雾,光靠这一个材质是做不出来的。
我的方案是分层:主体圆环用 Opaque 加 Alpha Clipping 做出稳定的形状,然后在上面再挂一层粒子系统或者单独的透明材质做能量烟雾。形状归形状,半透明特效归半透明特效,互不干扰。这样既保住了排序稳定,又拿到了半透明的视觉加分。如果你非要在一个材质里同时拿到半透明边缘和裁剪形状,也可以选 Transparent 并配合其他混合模式,但要做好心理准备:两个传送门同时出现在画面里时,排序问题大概率会找上门。
多人游戏或者场景里同时布置多个传送门时,这种差异会被放大。透明混合的传送门彼此交叠会出现随视角闪烁的排序错误;Opaque 加 Clipping 的传送门则像普通不透明物体一样稳定。我的经验是,传送门这种功能性的特效对象,稳定性优先于柔和的边缘观感,能 Op 就 Op。
最后分享一个我自己常用的检查路径:遇到任何“方形底图”类问题,先打开 Shader Graph 的 Graph Inspector,勾选 Alpha Clipping,再检查 Fragment 的 Alpha 端口有没有接通,最后用 Threshold 滑块从低往高推一遍看残留什么时候消失。这套流程熟练之后,几秒钟就能定位问题。最隐蔽的坑永远是那个:在材质面板上找开关,或者勾了选项却没连 Alpha,然后对着画面百思不得其解。希望这篇能把这两步彻底焊进你的肌肉记忆里。