编辑
2025-09-16
Unity
00

目录

DrawCall
概念
DC为什么会影响性能
如何降低DC(以下均称DrawCall)
打图集
动态批处理
概念
如何开启动态批处理
动态批处理的限制(满足的条件)
适合使用动态批处理的情况
静态批处理
概念
如何开启静态批处理

DrawCall

概念

  • CPU准备好渲染数据(顶点,纹理,法线,Shader等等)后,告知GPU开始渲染(将命令放入命令缓冲区)的命令;简单来说,一次DrawCall就是CPU准备好渲染数据通知GPU渲染的这个过程
  • 每次DrawCall,CPU都需要准备很多数据发送给GPU,那么如果DrawCall越多那么额外开销就越大。其实GPU的渲染效率是很强大的,往往影响渲染效率的都是因为CPU提交命令的速度。如果DrawCall太多CPU就会把大量时间花在提交DrawCall上,造成CPU过载,游戏卡顿。

DC为什么会影响性能

  • 每个 DrawCall 都需要进行 CPU 准备数据、切换状态、调用图形 API(OpenGL、DirectX等)等操作,都会有固定的CPU提交成本,而这些成本会随着DrawCall的数量增多,累积耗时到毫秒级别,从而占满 CPU 渲染线程(Render Thread)的时间;
  • 如果DrawCall太多,CPU 花太多时间准备批次,GPU 可能处于等待状态,从而导致帧率被CPU限制,而GPU其实还是空闲状态

如何降低DC(以下均称DrawCall)

打图集

  • 当多个 UI 元素或模型使用同一张图集时,它们就能共用同一个材质,CPU 可以一次性批量提交给 GPU,而不是每个小图单独提交,从而减少 DrawCall 次数;
  • 原本每个小图(不同纹理)都要单独一次 DrawCall,打成图集后统一用一张纹理,等于共享材质
  • UI 场景:假设界面上有 50 个按钮,每个按钮用一张独立的 PNG 图片 → 至少 50 个 DrawCall;如果打成一张图集 → 只要 1 个 DrawCall(前提:同一 Canvas、同层级、不被裁剪/遮挡打断)

动态批处理

概念

动态批处理是一种Unity在运行时由 CPU 自动将满足限制条件的多个动态物体网格合并成一个大网格,一次性提交给 GPU,从而减少 Draw Call 的技术

  1. 动态批处理是内置渲染管线中的重要优化手段,SRP(URP/HDRP)管线中主要采用SRP Batcher(我们之后会讲解);
  2. Unity中创建了一个对象,但是DrawCall并不是增长了1次,而是n次,是因为阴影、深度等贴图以及多Pass、透明、子网格、多材质都会增加DrawCall的次数

如何开启动态批处理

内置渲染管线(只适用于内置渲染管线): 勾选即可

Player Settings ——> Other Settings ——> Rendering ——> Dynamic Batching

image.png

动态批处理的限制(满足的条件)

  1. 顶点数量限制,在Unity版本2021之前是300,2021之后是225,也就是说顶点数量不能超过这个数;同时,顶点 * 顶点属性 <= 900;

    即:每个网格最多 225 或 300 个顶点,同时着色器使用的顶点属性不能超过900,顶点属性是在Shader中会用来进行渲染计算的数据,常用属性有顶点的 位置、法线、切线、多套UV纹理、顶点颜色、骨骼权重、骨骼索引等等

    对于简单Shader来说 一般至少需要 位置、法线、UV 3个属性,225 * 3 = 675 ,300 * 3 = 900,此时顶点满足条件,顶点 * 顶点属性也满足条件,会进行动态批处理

    若对于一些复杂Shader,假设该shader使用 5 个属性,那么网格的顶点上限就是 900 / 5 = 180 个顶点

    总结:只要超出225(Unity2021之前为300)顶点或900属性任意一个限制,该网格将不会被动态批处理

  2. 相同材质实例

    不同对象之间,必须使用同一个Material对象(同一内存引用),并且材质属性、Shader关键字、渲染状态必须完全一致

  3. 不能是SkinnedMeshRenderer(蒙皮网格渲染器)

    这里一般说的是骨骼动画模型,会用到SkinnedMeshRenderer;

    只有MeshRenderer(网格渲染器)和ParticleSystem(粒子系统)能进行动态批处理

    image.png

  4. 对象不能再变换中包含镜像

    即一个正比例缩放的游戏对象和一个负比例缩放的游戏对象不能放在一起批处理,其实就是Scale不能一个是1一个是-1

  5. 相同光照状态

    如果使用了光照烘焙中的光照贴图,那必须保持使用的是同一个光照贴图,并且 光照探针、反射探针、雾效开关等必须一致,否则渲染状态切换会打断批处理

  6. 同一渲染队列

    渲染队列(Render Queue)必须一致,比如都在 不透明 队列,否则会被排序拆开

  7. 材质不能开启 GPU Instancing

    开启了 Enable GPU Instancing 会让 Unity 用 Instancing 路径,而不是动态批处理(两者互斥)

  8. Shader最好单Pass

    否则每个Pass都有单独的DrawCall

适合使用动态批处理的情况

大量使用相同材质的小型动态网格,并且满足批处理条件,且顶点数低于 225(300)/900 属性限制

物体是动态的,位置、旋转、缩放会发生改变,不能用静态批处理时,首选动态批处理

使用场景:

  1. 游戏中的小道具、小物件;比如:地图上的金币、宝石、道具箱子、掉落物;
  2. 简单的动态环境元素;比如:旋转的风扇叶片等;
  3. 低顶点数的动态建筑元素,小路灯、小栅栏、路标等(材质相同、顶点少);
  4. 粒子系统的网格粒子(Mesh Particle),多个相同网格的小粒子,如果没用 GPU Instancing,也能走动态批处理,等等;

静态批处理

概念

静态批处理是一种在构建或者第一次运行时,对场景上勾选了Batching Static的物体进行网格合并,将多个静态物体网格会合并成一个大网格,一次性提交给 GPU,从而减少 Draw Call 的技术

如何开启静态批处理

将游戏对象的Inspector窗口中勾选Batching Static

image.png

一般静态批处理功能都是默认开启的,不管在内置渲染管线 还是 SRP 中

Player Settings ——> Other Settings ——> Rendering ——> Static Batching

image.png

本文作者:xuxuxuJS

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!