47.性能优化-CPU-图形-GPU Instancing
47.1 知识点
GPU Instancing 是什么
GPU Instancing 就是 GPU 实例化的意思,是一种减少 Draw Call、提高渲染效率的技术,主要用于批量绘制大量相同网格(Mesh)对象。
主要原理:
- 开启 GPU Instancing 后,Unity 会把一份网格和材质上传到 GPU。
- 同时会传递一批实例数据(包含每个物体的位置、旋转、缩放、颜色等)。
- GPU 通过实例化 ID 读取对应参数,动态计算世界坐标。
- 最终用一次 Draw Call 绘制出许多相同网格、相同材质的对象。
说人话:
CPU 用一次 Draw Call 告诉 GPU 要画一棵树,同时提供 N 棵树的坐标、旋转、缩放、颜色等数据,GPU 就能一次性批量绘制这 N 棵树。
注意:
- 与动态/静态批处理不同:动态/静态批处理需要在 CPU 端合并网格,会带来 CPU 合并计算与内存开销。
GPU Instancing 把计算负担更多交给 GPU,CPU 只负责传数据。 - 一个对象同时开启时优先级:静态批处理 > GPU Instancing > 动态批处理。
如何开启 GPU Instancing
材质设置:
- 在需要进行 GPU Instancing 的材质球中,勾选 Enable GPU Instancing。

- 任意渲染管线中都可使用该功能。
操作实践:
- 对 Cube 和 Sphere 关闭静态批处理。
- 项目设置中关闭动态批处理。
- 材质勾选 GPU Instancing。

- 先失活球体,运行后可见 GPU Instancing 一次绘制了三个 Cube。

- 运行时激活球体,因渲染顺序原因会多几次 Draw Call,但仍能看到两个 Cube 被一起绘制。


GPU Instancing 的使用限制
核心限制:
- 相同网格:所有对象必须使用同一网格。
- 相同材质:材质需一致,贴图和 Shader 关键字不能变化;颜色、额外属性可以通过实例数据变化。
- 材质必须启用:勾选材质球上的 Enable GPU Instancing。
- 不支持 SkinnedMeshRenderer:仅支持
MeshRenderer或Graphics.RenderMesh等 API 绘制的网格。
自定义 Shader 支持:
- 若是自定义 Shader,需要加入编译指令:
#pragma multi_compile_instancing
- 想支持不同颜色、金属度、透明度等,可参考官方文档:
https://docs.unity.cn/cn/2023.2/Manual/gpu-instancing-shader.html
操作实践:
- 材质和网格都相同才能合批绘制,比如三个球体可以一起绘制。

- 只激活一个球体和一个 Cube 时无法合批,即便材质相同,但网格不同也不能合批。

适合使用 GPU Instancing 的情况
适合:
- 大量相同物体(草地、森林、石头、瓦片、建筑模型、子弹等)。
- 实例之间只有少量差异(颜色、亮度、缩放比例、UV 偏移等)。
- 动态物体但网格与材质固定,性能瓶颈在 CPU。
动态批处理 CPU 开销大,静态批处理又不能移动,GPU Instancing 适合这种场景。
不适合:
- 每个物体材质或贴图不同,合批会被打断。
- 实例数量很少(几十个以内),GPU Instancing 可能比单独 Draw Call 更贵。
- 大量独立网格和材质,对象种类过多时收益小。
- SkinnedMeshRenderer(骨骼动画模型不支持)。
更多
Unity 还提供了相关 API 配合 GPU Instancing 使用,后续继续学习。
47.2 知识点代码
Lesson47_性能优化_CPU_图形_GPUInstancing.cs
public class Lesson47_性能优化_CPU_图形_GPUInstancing
{
#region 知识点一 GPU Instancing是什么?
// GPU Instancing 就是 GPU 实例化的意思
// 它是一种减少 Draw Call,提高渲染效率 的技术
// 主要用来批量绘制大量相同的网格(Mesh)对象
// 它的主要原理
// 当开启 GPU Instancing 后
// Unity 会将一份网格和材质上传到 GPU
// 并且还会传递一批实例数据(里面包含每个物体的位置、旋转、缩放、颜色等等)
// GPU 收到数据后,会通过对象的实例化 ID 找到对应的参数,动态计算世界坐标
// 让 GPU 在一次 Draw Call 中绘制出许多相同的对象
// 说人话
// GPU Instancing 利用 CPU 一次 Draw Call 告诉 GPU 的数据
// GPU 自己根据数据绘制 N 个不同但是材质相同、网格相同的对象
//
// 比如:
// CPU 只通过一次 Draw Call 告诉 GPU 要绘制树
// 但是告诉了 GPU 这里 N 棵树的坐标、旋转、缩放、颜色等等数据
// GPU 就利用这些数据批量的绘制 N 棵树
// 注意:
// 1.它和动态和静态批处理的原理区别在于
// 动态和静态批处理它们都需要在 CPU 端合并网格,再告诉 GPU,一个批次依然是一个大网格
// 这样在 CPU 端有合并计算和内存的开销
// 而 GPU Instancing 中 CPU 不会有太多额外开销(因为它只负责传递数据,并不再计算)
// 而是把开销交给了 GPU
// 因为需要在 GPU 中根据数据进行更多矩阵运算,来绘制对象
// 2.一个对象同时开启它们时,优先级为
// 静态批处理 > GPU Instancing > 动态批处理
#endregion
#region 知识点二 如何开启GPU Instancing
// 在想要进行 GPU Instancing 对象的材质球中
// 勾选 Enable GPU Instancing
// 在任意渲染管线中都可使用
#endregion
#region 知识点三 GPU Instancing的使用限制
// 1.相同网格
// 所有想要进行 GPU Instancing 处理的对象必须使用同一网格
// 2.相同材质(颜色、额外属性可以变化;贴图、Shader 关键字不能变化)
// 所有对象必须使用同一材质,并且 Shader 必须支持 GPU Instancing
// Unity 中默认 Shader 都支持它
// 如果是自定义 Shader,满足基本处理只需要加入编译指令
// #pragma multi_compile_instancing
// 如果想要支持不同颜色、金属度、透明度等等
// 可以查看官方文档:
// https://docs.unity.cn/cn/2023.2/Manual/gpu-instancing-shader.html
// 3.必须启用材质球上的 Enable GPU Instancing
// 4.不支持 SkinnedMeshRenderer(蒙皮网格渲染器)
// 只支持 MeshRenderer 或者 Graphics.RenderMesh 等 API 绘制的网格
// 等等
#endregion
#region 知识点四 适合使用GPU Instancing的情况
// 适合的情况
// 1.大量相同物体时
// 比如草地、森林、石头、瓦片、建筑模型、子弹等等
// 2.实例之间只有少量差异
// 不同颜色或亮度、不同缩放比例、不同 UV 偏移等等
// 3.动态物体,但是网格和材质固定,性能瓶颈在 CPU 时
// 动态批处理对 CPU 开销大;静态批处理又不能移动
// GPU Instancing 则既能支持移动,又减少 CPU 到 GPU 通信
// 等等
// 不适合的情况
// 1.每个物体的材质/贴图不同
// GPU Instancing 要求材质一致,贴图差异会打断合批
// 2.实例数量很少(几十个以内)
// 这种情况 GPU Instancing 开销可能反而比 Draw Call 更大
// 3.大量独立的网格和材质
// 如果对象种类太多,GPU Instancing 没啥用
// 4.SkinnedMeshRenderer(蒙皮网格渲染器)
// 骨骼动画模型不支持 GPU Instancing
// 等等
#endregion
#region 更多
// Unity 还提供了相关 API 配合 GPU Instancing 使用
// 之后的再继续学习
#endregion
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com