GameTech/URP 渲染实战

案例 22.3角度淡出:开启 Decal Shader Graph 的 Angle Fade进阶

目标:贴花在与投影方向接近平行的表面上自动淡出,消除拉伸。

Decal Projector 有 startAngleFade / endAngleFade 两个参数(0–180°,默认都是 180,即不淡出)。但只设置它们没有效果——还需要贴花材质的 Shader Graph 在 Graph Settings 里勾选 Angle Fade,它会为 Shader 生成 DECAL_ANGLE_FADE 关键字和对应的计算。URP 包自带的 Decal.shadergraph 没有勾选这一项。

.shadergraph 文件本质上是 JSON,Graph Settings 存在 UniversalDecalSubTarget 对象的 m_DecalData 字段里。本章把包里的 Decal.shadergraph 复制一份到 Ch22/DecalAngleFade.shadergraph,只改了两处:"angleFade": true,以及把 Shader 路径 m_Path 改为 Cookbook/Ch22。在编辑器里则只需打开 Graph、在 Graph Inspector 里勾选 Angle Fade。

淡出的计算在 C# 端预先打包好,摘自 URP 14 Runtime/Decal/Entities/DecalEntityManager.cs 的注释与代码:

// In the shader to remap from cosine -1 to 1 to new range 0..1  (with 0 - 0 degree and 1 - 180 degree)
// we do 1.0 - (dot() * 0.5 + 0.5) => 0.5 * (1 - dot())
// we actually square that to get smoother result => x = (0.5 - 0.5 * dot())^2
// Do a remap in the shader. 1.0 - saturate((x - start) / (end - start))
// After simplification => saturate(a + b * dot() * (dot() - 2.0))
float angleStart = startAngleFade / 180.0f;
float angleEnd = endAngleFade / 180.0f;
var range = Mathf.Max(0.0001f, angleEnd - angleStart);
cachedChunk.angleFades[arrayIndex] = new Vector2(1.0f - (0.25f - angleStart) / range, -0.25f / range);

也就是说,它没有在 Shader 里算反余弦求角度,而是把“夹角 0–180°”近似映射成 (0.5−0.5cosθ)2,再把重映射的系数在 CPU 上算好,Shader 里只剩一次乘加。这是一个很典型的“把非线性重映射的常量部分搬到 CPU”的优化。

图 22-4一张 UV 网格贴花从正上方投到箱子和球上。左:包自带的 Decal Shader Graph,箱子侧面、球的下半部分都被拉出长条;右:开启 Angle Fade 的 Graph,startAngleFade = 40°、endAngleFade = 70°,侧面上的贴花自然消失