URP 渲染实战 / 第 18 章 溶解、全息与护盾 / 案例 18.2
案例 18.2边缘发光:让溶解有“燃烧”的前沿入门
目标:在溶解的前沿加一条发光的边,可以是纯色硬边(科幻风格的“数字化消散”),也可以是从暗红到亮黄的渐变火边(燃烧)。
原理:阈值之上再划一条带
记 d = v − p:d < 0 的像素已经被裁掉;d 刚好大于 0 的像素“即将被溶掉”,它们就是前沿。取一个宽度 w,令
则 d=0 处 edge=1,d≥w 处 edge=0,中间线性过渡。用 edge 去查一张 Ramp 贴图(公共贴图 ramp_fire:左边暗紫,右边亮黄白),越靠近前沿越亮、越黄,往里逐渐变暗红——正好是燃烧的颜色分布。
片元函数如下:
Assets/Cookbook/Ch18/Dissolve.shader(节选:frag)
half4 frag(Varyings i, FRONT_FACE_TYPE face : FRONT_FACE_SEMANTIC) : SV_Target { half edge; DissolveClip(DissolveValue(i.uv, i.positionOS, i.positionWS), edge); half3 albedo = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, i.uv * _BaseMap_ST.xy + _BaseMap_ST.zw).rgb * _BaseColor.rgb; // 双面渲染时,背面(物体内壁)把法线翻过来,再压暗一点,看起来像“空心的内部” half3 normalWS = normalize(i.normalWS) * IS_FRONT_VFACE(face, 1.0h, -1.0h); albedo *= IS_FRONT_VFACE(face, 1.0h, 0.35h); // 前沿附近先“烧焦”变暗,再在最前沿发光 albedo *= 1.0h - 0.85h * smoothstep(0.0h, 0.6h, edge); half3 color = SimpleLighting(albedo, i.positionWS, normalWS, _Smoothness); half3 glow = _EdgeColor.rgb; if (_UseRamp > 0.5) glow *= SAMPLE_TEXTURE2D(_EdgeRamp, sampler_EdgeRamp, float2(edge, 0.5)).rgb; // edge^2:让发光集中在最前沿,向内快速衰减 color += glow * edge * edge; color = MixFog(color, i.fogFactor); return half4(color, 1); }
void main() { float edge; DissolveClip(DissolveValue(uv, posOS, positionWS), edge); vec3 albedo = texture(_BaseMap, uv * _BaseMap_ST.xy + _BaseMap_ST.zw).rgb * _BaseColor.rgb; // 双面渲染时,背面(物体内壁)把法线翻过来,再压暗一点,看起来像“空心的内部” vec3 N = normalize(normalWS) * (gl_FrontFacing ? 1.0 : -1.0); albedo *= gl_FrontFacing ? 1.0 : 0.35; // 前沿附近先“烧焦”变暗,再在最前沿发光 albedo *= 1.0 - 0.85 * smoothstep(0.0, 0.6, edge); vec3 color = SimpleLighting(albedo, positionWS, N, _Smoothness); vec3 glow = _EdgeColor.rgb; if (_UseRamp > 0.5) glow *= texture(_EdgeRamp, vec2(edge, 0.5)).rgb; // edge^2:让发光集中在最前沿,向内快速衰减 color += glow * edge * edge; color = MixFog(color, fogFactor); fragColor = vec4(color, 1.0); }
两处细节值得说。第一,发光项乘的是 edge * edge 而不是 edge:平方让亮度集中在最前沿、往里快速衰减,看起来更像一条细亮线而不是一片光晕。第二,在前沿后方先把反照率压暗(albedo *= 1 - 0.85 * smoothstep(0, 0.6, edge)),模拟纸张燃烧时火线前面先“烤焦”的那一圈,这比单纯加一条亮边可信得多。
HDR 颜色与 Bloom
_EdgeColor 用 [HDR] 标记,分量可以填到 4、5。URP 默认开启 HDR 时,相机颜色缓冲是浮点格式,能存下大于 1 的值;后处理 Bloom 会把超过阈值的部分提取出来模糊、叠回画面,产生“溢光”。没有后处理时,大于 1 的颜色会在最终输出时被截断成白色,你只能看到一条刺眼的白边——这是很多人“发光颜色怎么调都发白”的原因。

注意本书配图默认关闭后处理,以便看清 Shader 的原始输出;凡是标注“开启 Bloom”的图,都是在 Volume 里加了 Bloom(阈值约 1)和 Neutral Tonemapping。Bloom 的阈值、散射等参数见第 27 章。