渲染侧:DrawCall、Overdraw 与材质
特效性能问题里大概一半不在"模拟"而在"渲染"。这一节讲模拟之外的开销。
渲染开销的五个来源
| 开销来源 | 特征 | 应对手段 |
|---|---|---|
| DrawCall | 发射器越多越贵 | 合并发射器、减少材质切换 |
| Overdraw | 半透明大 Sprite 堆叠(烟、雾) | 减小 Sprite 尺寸、降低不透明度、减少叠放层数 |
| 顶点数 | Mesh 粒子 / Ribbon 段数 | Ribbon 的段数按距离折叠 |
| 材质复杂度 | 复杂的数学节点 / 多次采样 | 简化材质、使用 粒子材质函数 复用 |
| 半透明排序 | 大量半透明物互相排序 | 减少层数(与 overdraw 同源) |
Overdraw:最常见的隐形杀手
一片"看起来很大很漂亮"的烟雾 Sprite,如果半透明且尺寸巨大,每个像素都要跑一次像素着色器。屏幕上 30 个这样的 Sprite 叠在一起 = 同一像素着色器跑 30 次(overdraw 30 倍)。在 1080p 下这就是六千多万次像素操作。
判断方法:编辑器视口里用 Buffer Visualization → Shader Complexity(着色器复杂度视图),红色区域就是 overdraw 热点。
三招应对:
- 大 Sprite 能少则少(装饰用少而精的大 Sprite,不要堆量);
- 极远处的半透明 Sprite 改成不透明或干掉(远处的烟没人看得到细节);
- 烟雾类型的效果用"少层 + 大尺寸 + 高模糊感"而不是"多层 + 小尺寸"。
DrawCall 的合并空间
每个"材质 + 发射器"组合产生一个 DrawCall。合并思路:
- 同场景的多个小特效如果用同一个材质,可以合并成一个发射器(位置用脚本区分),DrawCall 从 N 变 1;
- 切换材质在 GPU 上是有成本的,批次内尽量让同材质的发射器相邻——这部分由引擎自动排序处理,但合并发射器是人工能做的。
Ribbon 与 Mesh 的顶点数
- Ribbon 拖尾的"段数"直接决定顶点数。短拖尾(剑光)28 段够,长拖尾(流星)才需要 100 段以上;
- Mesh 粒子的 LOD 别忘了——没有 LOD 的 Mesh 粒子在远处照旧全顶点渲染。
一个容易被忽略的带宽项:纹理
粒子纹理图集(Flipbook)尺寸越大、帧数越多,采样的带宽越高。移动端上常见的"省了一个粒子,费了一张 4K 翻页图集"就是这种问题。纹理选择原则:够用就好,图集尺寸 ≤ 512 是移动端的安全线。
