渲染侧:DrawCall、Overdraw 与材质

特效性能问题里大概一半不在"模拟"而在"渲染"。这一节讲模拟之外的开销。

渲染开销的五个来源

开销来源 特征 应对手段
DrawCall 发射器越多越贵 合并发射器、减少材质切换
Overdraw 半透明大 Sprite 堆叠(烟、雾) 减小 Sprite 尺寸、降低不透明度、减少叠放层数
顶点数 Mesh 粒子 / Ribbon 段数 Ribbon 的段数按距离折叠
材质复杂度 复杂的数学节点 / 多次采样 简化材质、使用 粒子材质函数 复用
半透明排序 大量半透明物互相排序 减少层数(与 overdraw 同源)

Overdraw:最常见的隐形杀手

一片"看起来很大很漂亮"的烟雾 Sprite,如果半透明且尺寸巨大,每个像素都要跑一次像素着色器。屏幕上 30 个这样的 Sprite 叠在一起 = 同一像素着色器跑 30 次(overdraw 30 倍)。在 1080p 下这就是六千多万次像素操作。

判断方法:编辑器视口里用 Buffer Visualization → Shader Complexity(着色器复杂度视图),红色区域就是 overdraw 热点。

三招应对:

  1. 大 Sprite 能少则少(装饰用少而精的大 Sprite,不要堆量);
  2. 极远处的半透明 Sprite 改成不透明或干掉(远处的烟没人看得到细节);
  3. 烟雾类型的效果用"少层 + 大尺寸 + 高模糊感"而不是"多层 + 小尺寸"。

DrawCall 的合并空间

每个"材质 + 发射器"组合产生一个 DrawCall。合并思路:

  • 同场景的多个小特效如果用同一个材质,可以合并成一个发射器(位置用脚本区分),DrawCall 从 N 变 1;
  • 切换材质在 GPU 上是有成本的,批次内尽量让同材质的发射器相邻——这部分由引擎自动排序处理,但合并发射器是人工能做的。

Ribbon 与 Mesh 的顶点数

  • Ribbon 拖尾的"段数"直接决定顶点数。短拖尾(剑光)28 段够,长拖尾(流星)才需要 100 段以上;
  • Mesh 粒子的 LOD 别忘了——没有 LOD 的 Mesh 粒子在远处照旧全顶点渲染。

一个容易被忽略的带宽项:纹理

粒子纹理图集(Flipbook)尺寸越大、帧数越多,采样的带宽越高。移动端上常见的"省了一个粒子,费了一张 4K 翻页图集"就是这种问题。纹理选择原则:够用就好,图集尺寸 ≤ 512 是移动端的安全线。