手游阴影优化:从 Frame Debugger 里的四行字说起 起因某次用 Frame Debugger 查一个项目的渲染,展开MainLightShadow节点,看到这样一段:▼ MainLightShadow ▼ RenderShadows ▼ Cascade 0 Draw Mesh (x45) ▼ Cascade 1 Draw Mesh (x80) ▼ Cascade 2 Draw Mesh (x120) ▼ Cascade 3 Draw Mesh (x150)四个级联加起来 395 次绘制提交。而主 Pass 只有 200 次。也就是说,这个项目为了画阴影,干了比画游戏本身还多的活。而玩家在手机上几乎注意不到四十米外那些石头的影子。这篇就讲清两件事:级联阴影到底是什么,以及手游上该怎么配。一、阴影贴图的固有矛盾实时阴影的原理不复杂:从光源的视角渲染一张深度图,记录从光的角度看,每个方向最近的遮挡物有多远。渲染时再拿这张图比对,就知道某个像素有没有被挡住。问题出在平行光上。太阳是平行光,它照亮的是整个场景。而阴影贴图的分辨率是固定的,于是:一张 2048×2048 的阴影贴图 覆盖 150 米: 2048 ÷ 150 ≈ 每米 13.6 像素 → 脚下阴影边缘一个像素约 7cm → 锯齿明显 覆盖 15 米: 2048 ÷ 15 ≈ 每米 136 像素 → 脚下精细 → 但 15 米外完全没影子近处要精度,远处要覆盖,一张图给不了。二、级联的思路突破口在一个观察:远处的物体在屏幕上本来就只占几个像素,它的阴影不需要那么高的精度。所以把视野按距离切段,每段配一张自己的阴影贴图:摄像机 │ ┌────────┼──────────────┬─────────────────┬───────────┐ │Cascade0│ Cascade 1 │ Cascade 2 │ Cascade 3 │ │ 0-15m │ 15-40m │ 40-90m │ 90-150m │ └────────┴──────────────┴─────────────────┴───────────┘ ↓ ↓ ↓ ↓ 2048² 2048² 2048² 2048² 136px/m 46px/m 41px/m 34px/m 精度极高 精度高 精度中 精度低四张图的像素数完全一样,但覆盖的世界范围不同。近处那张被浪费在很小的区域上,所以密度极高。着色时,Shader 按像素深度判断它属于哪一级,去对应的图里采样。这就是Cascade 0~3的含义——不是四个效果层级,是四个距离分段。三、成本到底在哪这里有个流传很广的说法:“4 级联 场景被画 4 遍”。这个说法不准确。实际上每个级联只渲染落在它范围内的物体。理想情况下物体按距离分布,每个物体只进一个级联,总渲染量大致等于场景画一遍。但成本确实随级联数增长,原因是另外三个:固定开销每个级联是一次独立的渲染 Pass:设置 RenderTarget、Clear、提交、在移动端还要 resolve 一次 tile。这些开销和里面有多少物体无关。四个级联就是四份。大物体被重复提交这是最容易被忽略的一项。一块 100 米长的地形,横跨所有级联范围: Cascade 0 → 画它(裁剪后的一部分) Cascade 1 → 画它 Cascade 2 → 画它 Cascade 3 → 画它 ↑ 同一个物体提交 4 次,顶点处理 4 次大地形、长条建筑、连续的墙体,都是这类问题的来源。它们才是画了好几遍的真正主角。内存与带宽URP 把所有级联塞进一张 Atlas:1 级联: 2048×2048 约 8 MB 4 级联: 4096×4096 约 32 MB显存占用四倍,每帧的写入和采样带宽也随之上去。在手机上,这个带宽开销往往比渲染计算本身更要命——它直接转化成发热和降频。四、怎么判断自己的阴影贵不贵不用猜,Frame Debugger 里数一下就行。把各级联的 Draw Mesh 数量加总,和主 Pass 对比 阴影 220 / 主 Pass 200 → 比例 1.1,正常 阴影 395 / 主 Pass 200 → 比例 2.0,偏贵,该动手了再看分布。如果远处级联的物体数特别高(像开头那个例子,Cascade 3 有 150 个),说明大量远处小物件在投阴影。这部分是纯浪费:范围大、精度低、玩家看不清。五、按性价比排的优化顺序第一步:砍 Max DistanceURP Asset → Shadows → Max Distance这是最容易捡到的收益,而且很多项目这个值从来没动过。150m → 阴影 Pass 要处理 150 米内所有物体 40m → 物体数可能直接少七成 画面观感几乎没有损失远处阴影本来就模糊、被雾或景深盖掉,砍掉基本无感。手游常用 20~40 米。第二步:减级联数低端档: Cascade 1, Max Distance 20, Hard Shadows 中端档: Cascade 2, Max Distance 40, Hard Shadows 高端档: Cascade 4, Max Distance 80, Soft Shadows手游视距本来就近,4 级联多数情况下是在为看不见的东西付费。俯视角、卡牌、棋盘类游戏视野固定且近,1 级联完全够用,级联机制对它们没有意义。第三步:处理大物体地形和大型建筑单独拎出来关掉投影:Renderer → Cast Shadows → Off它们的阴影改用烘焙 Lightmap,或者直接在贴图里画。地形自己投自己的阴影在手游里性价比很低。第四步:关小物件投影石头、杂物、小道具的阴影没人会注意。写个工具批量处理:#ifUNITY_EDITORusingUnityEditor;usingUnityEngine;usingUnityEngine.Rendering;publicstaticclassShadowCasterAudit{privateconstfloatSizeThreshold1.5f;[MenuItem(Tools/关闭小物件投影)]privatestaticvoidDisableSmallCasters(){intcount0;foreach(varrinObject.FindObjectsOfTypeMeshRenderer()){if(r.shadowCastingModeShadowCastingMode.Off)continue;if(r.bounds.size.magnitudeSizeThreshold)continue;Undo.RecordObject(r,Disable Shadow Casting);r.shadowCastingModeShadowCastingMode.Off;count;}Debug.Log($已关闭{count}个小物件的阴影投射);}}#endif跑完回头再看 Frame Debugger,各级联的物体数应该明显下降。第五步:远处换假阴影角色脚下贴一个圆形半透明贴片(Blob Shadow),成本接近于零。远处只需要这里有个东西站着的视觉提示,精确形状毫无必要。很多上线手游的做法是:近处角色用实时阴影,超过一定距离切成 Blob,再远干脆不要。六、Split 比例值得单独调级联的分界点默认值往往不是最优的。默认: │ C0 │ C1 │ C2 │ C3 │ 10% 25% 50% 100% C0 只占 10%,近处那张高精度贴图浪费在太小的范围里 C3 吃掉后一半,精度低但也确实看不出偏向近处会更合理:│ C0 │ C1 │ C2 │ C3 │ 6% 15% 35% 100%调的时候打开可视化:Scene 视图 → Shading Mode → Shadow Cascades 蓝 Cascade 0 绿 Cascade 1 黄 Cascade 2 红 Cascade 3把角色站位和主要战斗区域调进蓝绿色范围,所见即所得。七、两个必然伴随的画质问题级联不是免费的,它引入了两类瑕疵。级联接缝。相邻级联精度不同,分界处能看到阴影质量突变,而且这条线会随摄像机移动,很显眼。URP 2022 之后有 Cascade Blending 可以缓解,也可以把分界点挪到视觉不敏感的距离。阴影爬行。摄像机移动时阴影贴图的采样网格跟着平移,边缘像素会跳动。URP 内部做了 texel snapping 缓解,但级联范围大时仍会有。提高分辨率、缩小 Max Distance、开软阴影都能减轻。这两个问题的共同点是:Max Distance 越小,它们越轻。又一个砍距离的理由。八、一张配置参考表游戏类型级联数Max Distance分辨率软阴影俯视角 / 卡牌 / 棋盘115~25m1024关手游低端档120m1024关手游中端档240m2048关手游高端档480m2048开第一人称射击2~350m2048开开放世界(需配合激进剔除)4100m2048开分辨率超过 2048 在移动端带宽吃不住,不建议。小结1. Cascade 0~3 是按距离分的四个阴影贴图,不是四个质量档 2. 真正的成本不是场景画四遍,而是: 四次 Pass 的固定开销 大物体重复提交 Atlas 的内存带宽 3. 诊断方法:Frame Debugger 里各级联物体数加总, 和主 Pass 比。超过 1.5 倍就该优化 4. 优化顺序: Max Distance 砍小 → 减级联 → 大物体关投影 → 小物件关投影 → 远处换假阴影 5. 手游的安全起点:1~2 级联,Max Distance 20~40m 6. 调 Split 比例时开 Scene 视图的 Shadow Cascades 可视化 7. Max Distance 越小,接缝和爬行这两个画质问题也越轻最后一句:阴影是手游里最容易被过度配置的系统。它的默认值是按 PC 场景设计的,原封不动搬到手机上,等于白送出去一大块性能预算。