前言
上一篇《从入门到图片扫光》介绍了 Shader Graph 的基本操作。这篇继续做溶解效果,再给溶解边缘加上颜色和发光。
下面同样以 Unity 2022.3、URP 与 Shader Graph 14 为例,不同版本的界面和选项可能有所不同。
先看一下效果:


先把图片显示出来
新建一个 Sprite Unlit Shader Graph 和对应材质,创建 Texture 2D 属性 MainTex,放入一张带透明背景的图片。用 Sample Texture 2D 采样,将 RGBA 输出连接到 Fragment 的 Base Color,A 输出连接到 Alpha。

把材质赋给一张没有父级遮罩的 Image,Color 保持白色。这里先用独立完整图片,Image 的 Type 选 Simple;如果想通过 Source Image 换图,可以按上一篇的方法设置 _MainTex 主纹理。
确认图片和透明背景正常显示后,再开始做溶解。
溶解效果
效果分析
接下来做溶解效果,让图片一点点消失。这里我们用一张噪声图,控制图片的哪些地方先消失、哪些地方后消失。

把过程暂停下来对比一下,最初是完整的图片,溶解后只剩下一部分:


在刚才显示图片的节点基础上,创建 Texture 2D 属性 NoiseTex,放入一张灰度噪声图,用另一个 Sample Texture 2D 采样。
可以先把噪声采样结果连接到 Base Color,看看这张图。不同位置有深有浅,对应的数值在 0---1 之间。接下来根据这些数值,决定哪些地方先消失。

灰度噪声的 RGB 通道相同,这里取 R 就可以了。注意不要取 A,很多噪声图的 Alpha 全是 1,取出来只会得到一张白图。
Step函数
Step 有 Edge 和 In 两个输入:当 In ≥ Edge 时输出 1,否则输出 0。Step 节点文档
比如 Edge 为 0.5,输入 0.2 会得到 0,输入 0.8 会得到 1。原来连续变化的灰度,就被分成了黑白两种区域。

创建 Float 属性 Progress,先填 0.5。再创建 Step,噪声采样的 R 接到 In,Progress 接到 Edge,然后将 Step 的 Out 接到 Preview。
这时候可以先把 Progress 调到 0.8,再调到 0.2,对比白色区域的大小。阈值越小,满足"大于等于"的位置越多,所以白色区域会变多。


这里需要注意,虽然属性命名为 Progress,但它控制的是 Step 的阈值。下面把白色区域作为"要擦掉的部分",所以在这套连接中,Progress 越小,图片消失得越多。
修改图片的Alpha
黑白区域确认正确后,再把它接回原图。
对比溶解前后的 Alpha,也能看到白色的可见区域被挖去了一部分:


遮罩中的白色表示要擦掉的位置,可以对照两张图里的红框看:


先创建 One Minus,输入接 Step 的结果。这个节点做的就是"1 减去输入值":原来为 1 的擦除区变成 0,原来为 0 的保留区变成 1。
再创建 Multiply,将原图 A 与 One Minus 的输出相乘,结果接到 Fragment 的 Alpha。Base Color 则恢复连接原图采样颜色。
这样,原来透明的地方仍然透明,原来可见的地方又被噪声挖去了一部分。对应的计算就是:
最终Alpha = 原图Alpha × (1 - Step结果)
下面两张图用的是原图 Alpha 减去 Step 结果;如果按图连接,可以在 Subtract 后面加一个 Saturate,将结果限制在 0---1。Step 只输出 0 或 1 时,这与上面的乘法结果相同,半透明边缘也一样。乘法的好处是中间结果不会出现负值。


保存后,手动减小 Progress,可以看到图片逐渐消失;再增大 Progress,图片就逐渐恢复。想确认两个端点,可以分别填略大于 1 和略小于 0 的值,把噪声恰好等于 0 或 1 的情况也包含进去。
目前改变的是参数,并不会自动播放动画。先手动确认效果正确,再用动画或脚本驱动参数即可。

带边缘颜色的溶解
1.效果分析
前面已经可以让图片逐渐消失。接下来希望消失的边界有一圈颜色,可以先看看这圈边缘应该放在哪里。
假设 Progress 为 0.7,边缘宽度为 0.1。我们可以把噪声分成三部分:小于 0.7 的部分保留原图,大于等于 0.7 且小于 0.8 的部分显示边缘色,大于等于 0.8 的部分透明。

因此需要两个阈值,分别是 Progress 和 Progress 加上边缘宽度。对同一张噪声做两次 Step,再将两个结果相减,就能取出中间这一段。
2.生成边缘区域
创建 Float 属性 OutlineWidth,先填 0.1,宽度不能小于 0。保留前面的 Step,再创建一个新的 Step,它们的 In 都接同一个噪声 R。
第一个 Step 的 Edge 仍然接 Progress。第二个 Step 的 Edge 接一个 Add,Add 的两个输入分别是 Progress 和 OutlineWidth。
可以对比两个 Step 的预览。因为第二个阈值更大,所以它的白色区域更小。

接下来创建 Subtract,A 接第一个 Step 的输出,B 接第二个 Step 的输出。可以看到,大块白色区域消失了,只留下两个范围之间的一圈白色。
边缘遮罩 = 第一个Step结果 - 第二个Step结果

保持 Progress 不变,只调整 OutlineWidth,可以观察边缘的变化。这里控制的是噪声数值区间,所以边缘在画面上不一定处处等宽,也不是固定几个像素。
3.给边缘添加颜色
这里分两路计算:一路保留图片本身的颜色,另一路计算边缘颜色,最后再相加。
先创建一个 One Minus,输入接第一个 Step 的输出,得到不包含边缘的本体区域。再创建 Multiply,将它与原图采样的 RGBA 相乘,得到本体颜色;这里只使用结果中的 RGB。
然后创建 Color 属性 OutlineColor,与刚才 Subtract 得到的边缘遮罩相乘,得到边缘颜色。用 Add 将本体颜色和边缘颜色相加,输出接到 Base Color:
最终RGB = 原图RGB × (1 - 第一个Step结果) + 边缘颜色 × 边缘遮罩
这时候,本体区域显示原图,边缘区域显示 OutlineColor。
还需要修改一下 Alpha。将溶解小节中用于 Alpha 的 One Minus 改接第二个 Step 的输出,后面与原图 A 相乘的连接保持不变。注意不要修改刚才用于本体颜色的 One Minus:
最终Alpha = 原图Alpha × (1 - 第二个Step结果)
原因是现在要等噪声大于等于 Progress 加 OutlineWidth 时才透明。如果还用第一个 Step 控制 Alpha,中间这一圈边缘也会被擦掉,结果就是颜色已经连好了,画面上却看不到。
下面这张图也是先分别计算本体和边缘,再用 Add 合并。图中的本体分支使用"原图 Alpha 减去第一个 Step"乘原图颜色;我们这里使用"1 减去第一个 Step",原图透明度统一放到最终 Alpha 中,避免半透明边缘在颜色和 Alpha 上重复相乘。


最后可以分别改边缘颜色、宽度和 Progress,观察变化。想让图片连同边缘完全消失,需要让 Progress 加 OutlineWidth 也小于 0。例如 OutlineWidth 为 0.1,Progress 可以继续降到 -0.11;只把 Progress 调到 0,仍可能留下一圈边缘。
外发光
现在边缘已经有颜色了,怎么让它像前面动图里一样发光呢?除了提高颜色亮度,还需要用到 Bloom 后处理,让亮的地方产生向外散开的光晕。
先保持刚才的节点连接不变,只修改边缘颜色。选中 Blackboard 中的边缘 Color 属性,把 Mode 改成 HDR,再在材质的颜色面板中提高 Intensity。


还要确认 URP Asset 的 HDR 已开启,相机也允许 HDR 渲染,这样大于 1 的亮度值才能保留到后处理。这里说的是 HDR 渲染,不需要使用 HDR 显示器。
之后在影响演示相机的 Volume 中,选择 Add Override → Post-processing → Bloom,勾选需要覆盖的参数,把 Intensity 调到大于 0,再调整 Threshold。相机需要启用相应后处理,Volume 的作用范围与相机设置也要匹配。URP 14 的 Bloom 设置说明

这里要注意 Canvas 的渲染模式。Screen Space - Overlay 的 UI 通常在相机后处理之后才绘制,所以即使颜色很亮,也不会经过这个相机的 Bloom。做这个效果时,需要让 UI 由开启了后处理的相机渲染,例如使用 Screen Space - Camera,并指定对应的相机。

可以保持颜色不变,先关闭 Bloom,再打开,对比有没有向外扩散的光晕。再保持 Bloom 开启,只调整 HDR 颜色强度,观察光晕怎样变化。这样就能分清哪些变化来自 Shader 的边缘颜色,哪些来自后处理。
常见问题处理
1.溶解的方向与预期相反
先单独预览 Step 的输出,检查 In 和 Edge 是否接反。本文把白色区域定义为擦除区,因此阈值越小,擦除范围越大。可以先手动降低 Progress,确认白色区域逐渐变多,再将它用于动画控制。
2.边缘不显示,或者溶解结束后仍有残留
先把边缘带单独接到 Preview。如果已经能看到一圈白色区域,但是最终画面没有颜色,检查 Alpha 是否提前把边缘带擦掉了。
如果结束后仍然残留一圈,需要让第二个阈值 Progress + OutlineWidth 也小于噪声的最小值,不能只让第一个阈值到达终点。
3.边缘颜色很亮,但是没有光晕
先确认相机启用了后处理,Volume 中的 Bloom 已生效,再检查 UI 是否经过这个相机的后处理。Screen Space - Overlay 的 UI 不能直接按相同方式得到光晕,具体需要根据 Canvas 与相机的渲染顺序处理。
到这里,溶解、边缘颜色和外发光就都完成了。大家可以换一张噪声图,再调调进度、边缘宽度和颜色,看看效果有什么变化。
下一篇继续用图片做精灵描边:从周围像素的 Alpha 判断边界,再处理描边厚度和显示范围。
后面也会找个时间,把这个系列的所有资源整理好,全部开源给大家。
创作不易,如果觉得这篇文章对你有所帮助,可以动动小手,点个赞哈,ღ( ´・ᴗ・` )比心