简述
指示GPU绘制图像需要花费时间。为其提供数据(包括网格和材质属性)也需要时间。我们已经知道有两种方法可以减少DrawCall的数量,即静态和动态批处理。
Unity可以将静态对象的网格合并为更大的静态网格,从而减少DrawCall数量。但只有使用相同材质的对象才能以这种方式组合,它是以存储更多网格数据为代价的。启用动态批处理后,Unity在运行时会对视图中的动态对象执行相同的操作。但仅适用于小型网格,否则会适得其反,CPU开销会变得非常大。
还有另一种方法,被称为GPU Instancing 或GPU实例化 。与动态批处理一样,此操作在运行时针对可见对象完成。核心思想是让GPU一次性渲染同一网格多次。因此,它不能组合不同的网格或材质,但不局限于小网格。GPU Instancing非常适用于处理大量相同物体(同一Mesh和同一Material),比如建筑物/树/草等重复出现的物体。
原理
GPU Instancing 也是一种 Batching,用于渲染网格的多个副本;它是将基础网格对象传递给 GPU 后,充分利用 Instancing Buffer 的方法,传递多个网格实例位置、朝向与颜色等其他属性构成的 Instancing Buffer 到 GPU,避免了反复传递多个基础网格对象在世界空间下变化后的顶点数据和其他额外数据,所有的实例都会引用同一个基础网格对象,非常适合用于创建植被、石头等场景中大量重复的网格对象;
每个批次都需要自己的矩阵数组,此数据发送到GPU并存储在内存缓冲区中,在Direct3D中称为常量缓冲区(CBUFFER),在OpenGL中称为统一(uniform)缓冲区。这些缓冲区具有最大容量限制,它限制了一个批次中可以容纳多少个实例。因此当物体数量足够多时,即便这些物体都使用的相同网格与材质并开启了GPU Instancing,也可能会分成几个批次去绘制;
开启条件
- 有一个MeshRenderer组件,或是由Graphics.DrawMesh产生,或是由 Graphics.DrawMeshInstanced、Graphics.DrawMeshInstancedIndirect产生。不支持SkinnedMeshRenderer;
- shader必须支持GPU Instancing;
- GPU Instancing允许实例物体具有不同的Transform,但如果想要创建更多的变体,比如不同颜色的变体,你需要修改shader, declare _Color as an instanced property,然后在脚本中通过MaterialPropertyBlock修改实例的颜色;
- 优先级冲突:SRP Batcher|Static Batching > GPU Instancing > Dynamic Batching;若同时开启,Unity只会执行优先级更高的SRP Batcher和Static Batching;