47.GPU Instancing

47.性能优化-CPU-图形-GPU Instancing


47.1 知识点

GPU Instancing 是什么

GPU Instancing 就是 GPU 实例化的意思,是一种减少 Draw Call、提高渲染效率的技术,主要用于批量绘制大量相同网格(Mesh)对象。

主要原理:

  1. 开启 GPU Instancing 后,Unity 会把一份网格和材质上传到 GPU。
  2. 同时会传递一批实例数据(包含每个物体的位置、旋转、缩放、颜色等)。
  3. GPU 通过实例化 ID 读取对应参数,动态计算世界坐标。
  4. 最终用一次 Draw Call 绘制出许多相同网格、相同材质的对象。

说人话:
CPU 用一次 Draw Call 告诉 GPU 要画一棵树,同时提供 N 棵树的坐标、旋转、缩放、颜色等数据,GPU 就能一次性批量绘制这 N 棵树。

注意:

  1. 与动态/静态批处理不同:动态/静态批处理需要在 CPU 端合并网格,会带来 CPU 合并计算与内存开销。
    GPU Instancing 把计算负担更多交给 GPU,CPU 只负责传数据。
  2. 一个对象同时开启时优先级:静态批处理 > GPU Instancing > 动态批处理

如何开启 GPU Instancing

材质设置:

  1. 在需要进行 GPU Instancing 的材质球中,勾选 Enable GPU Instancing
  2. 任意渲染管线中都可使用该功能。

操作实践:

  1. 对 Cube 和 Sphere 关闭静态批处理。
  2. 项目设置中关闭动态批处理。
  3. 材质勾选 GPU Instancing。
  4. 先失活球体,运行后可见 GPU Instancing 一次绘制了三个 Cube。
  5. 运行时激活球体,因渲染顺序原因会多几次 Draw Call,但仍能看到两个 Cube 被一起绘制。

GPU Instancing 的使用限制

核心限制:

  1. 相同网格:所有对象必须使用同一网格。
  2. 相同材质:材质需一致,贴图和 Shader 关键字不能变化;颜色、额外属性可以通过实例数据变化。
  3. 材质必须启用:勾选材质球上的 Enable GPU Instancing
  4. 不支持 SkinnedMeshRenderer:仅支持 MeshRendererGraphics.RenderMesh 等 API 绘制的网格。

自定义 Shader 支持:

  1. 若是自定义 Shader,需要加入编译指令:
#pragma multi_compile_instancing
  1. 想支持不同颜色、金属度、透明度等,可参考官方文档:
    https://docs.unity.cn/cn/2023.2/Manual/gpu-instancing-shader.html

操作实践:

  1. 材质和网格都相同才能合批绘制,比如三个球体可以一起绘制。
  2. 只激活一个球体和一个 Cube 时无法合批,即便材质相同,但网格不同也不能合批。

适合使用 GPU Instancing 的情况

适合:

  1. 大量相同物体(草地、森林、石头、瓦片、建筑模型、子弹等)。
  2. 实例之间只有少量差异(颜色、亮度、缩放比例、UV 偏移等)。
  3. 动态物体但网格与材质固定,性能瓶颈在 CPU。
    动态批处理 CPU 开销大,静态批处理又不能移动,GPU Instancing 适合这种场景。

不适合:

  1. 每个物体材质或贴图不同,合批会被打断。
  2. 实例数量很少(几十个以内),GPU Instancing 可能比单独 Draw Call 更贵。
  3. 大量独立网格和材质,对象种类过多时收益小。
  4. 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

×

喜欢就点赞,疼爱就打赏