Unity drawcall性能优化

drawcall优化

一、什么是drawcall

     drawcall是cpu对图形绘制接口的调用,CPU通过调用图形库(directx/opengl)接口,命令GPU进行渲染操作。

CPU和GPU之间的数据是通过命令缓冲区进行传输的。命令缓冲区包含了一个队列,由CPU向其中添加命令,GPU去读取命令,添加和读取的命令都是相互独立的。

当CPU需要渲染一个对象时,就可以向命令缓冲区中添加命令,而当GPU完成上一个渲染任务后,就会从命令缓冲区中再取出一条命令并执行它。在渲染绘制过程有很多命令,drawcall就是其中一种。

二、drawcall为什么需要优化

CPU 瓶颈:每一次 Draw Call,CPU 都需要向 GPU 发送大量的指令和数据,比如设置材质、传递矩阵、绑定纹理等。这个过程本身会消耗 CPU 大量时间。GPU 空闲:CPU 在为下一次 Draw Call 做准备时,GPU 可能正处于空闲状态,等待新的任务。这种 CPU 和 GPU 之间的 “等待” 是性能浪费的主要原因之一。优化目标:尽可能地减少 CPU 发送给 GPU 的 Draw Call 数量,让 CPU 有更多时间处理游戏逻辑、物理等,同时让 GPU 能更高效地并行处理渲染任务。

三、drawcall的解决方法

渲染10个模型,如果每次渲染时都调用一次Drawcall,那么总共需要调用10次Drawcall;如果10个模型能够合并调用,那么只需要调用一次drawcall,减少了CPU与GPU的指令交互的时间,这种合并调用的操作就是合批。合批Draw Call Batching)就是drawcall的解决办法。

四、如何合批

1、什么是合批?

将多个渲染对象的CPU渲染指令统一起来向GUP提交,将多个独立Drawcall合并成给一个drawcall的指令方式,简称合批,又叫绘制调用批处理。

绘制调用批处理是一种组合mesh的绘制调用优化方法,以便Unity可以在较少的绘制调用中渲染纹理。

Unity提供以下内置的绘制调用批处理方法:

静态批处理(Static batching

动态批处理(Dynamic batching

SRP Batcher (只在UPR或SRP项目中有效)

GPU Instancing

2、合批规则

对于合批是有些限定的,基本规则如下: 

1)带有如MeshRenderTrailRenderLineRenderParticleSystemSpriteRender组件的mesh支持合批。

2)带有SkinMeshRender布料模拟的mesh是不能合批。

五、静态批处理

1、什么是静态批处理

静态批处理是一种绘制调用批处理方法,它将不移动的mesh的drawCall统一起来,以减少绘制调用。

2、原理

将场景中静止不动(Mesh不动)的物体(如地形、建筑、道具)在烘焙时合并成一个或多个大的网格。

3、使用方法

Inspector 面板中,勾选物体的 Static 选项(或使用StaticEditorFlags)。启用 Unity 的静态批处理功能(在 Player Settings -> Other Settings -> Rendering 中勾选 Static Batching)

4、优缺点

优点:

显著减少 Draw Call 数量。对 GPU 友好,因为合并后的网格可以更高效地被渲染。

缺点:

增加了内存占用,因为需要存储合并后的网格数据。只适用于静态物体,动态物体无法使用。

5、静态批处理的过程

需要合批的物体应该设置为static,表示GameObject对象不能被移动并且需要合批。对于静态mesh,Unity将它们的组合合并渲染。静态批处理将组合的mesh转换为世界空间,并为它们构建一个共享的顶点索引缓冲区。对于可见模型,Unity执行一系列简单的绘制调用,每个调用之间几乎没有状态变化。静态批处理不会减少绘制调用的数量,而是减少它们之间渲染状态更改的数量静态批处理比动态批处理更有效,因为静态批处理不会转换CPU上的顶点。

6、静态合批的规则

          1)必须符合合批的基本规则

          2)必须是static类型的mesh,不能移动的mesh

          3)mesh是一样的并且材质相同,有meshRender组件

        4)在大多数平台上,批处理限制为 64k 个顶点和 64k 个索引(OpenGLES 上为 48k 个索引,在 macOS 上为 32k 个索引),如果超过会合批成另外个mesh。

        5)合批的mesh如果Scale不同无法合批,合批会被打断

        6)相同顶线信息和UV的才能一起合批:如:Unity可以对使用顶点位置、顶点法线和一个UV的mesh进行批处理,但不能与顶点坐标、顶点法线、UV0、UV1和顶点切线的mesh一起批处理

          8)Mesh Renderer component组件不使用具有DisableBatching标记设置为true的着色器的任何材质。

         9)不同的贴图信息的无法合批。如:烘焙的光照贴图不相同的mesh无法合批在一起

          10)模型的GameObject必须是active状态

          11)位置不相邻的中间夹杂着不同材质的其他物体,不会批处理。

12)动态改变Render.material会造成一个新的material拷贝,应该使用render.shareMaterial,保证材质共享,否则不能合批。

六、动态批处理

1、动态合批的定义

对于足够小的mesh,这将在CPU上变换它们的顶点,将相似的顶点分组在一起,并在一次绘制调用中渲染它们。 

2、原理

Unity 会自动将材质相同且满足一定条件的动态物体(如敌人、子弹)合并成一个批次进行渲染。

3、使用条件:

物体必须使用相同的材质。物体的网格必须足够小(顶点数和索引数有上限)。物体不能包含骨骼动画。

4、优缺点

优点:

无需手动操作,Unity 自动处理。对动态物体有效。

缺点:

有严格的使用条件,很多情况下无法满足。合并过程本身也会消耗一定的 CPU 时间。

5、动态合批规则

1动态批处理无法应用于包含超过 900 个顶点属性和 300 个顶点的网格。这是因为网格的动态批处理具有每个顶点的开销。

例如,如果着色器使用顶点位置、顶点法线和单个 UV,则 Unity 最多可以批处理 300 个顶点。但是,如果着色器使用顶点位置、顶点法线、UV0、UV1 和顶点切线,则 Unity 只能批处理 180个顶点。

2)Unity 无法将动态批处理应用于在其变换组件中包含镜像的对象。例如,如果一个对象的比例为 1,而另一个游戏对象的缩放比例为 –1,Unity 无法将它们批处理在一起。

     3)如果对象使用不同的material实例,Unity无法将它们批处理在一起,即使它们本质上是相同的。

Shadow cast是个例外,尽管Shadow casters使用不同的材质,但是只要它们的材质中给Shadow Caster Pass使用的参数是相同的,他们也能够进行Dynamic batching。

 4)具有lightmap的GameObject具有其他渲染器参数。这意味着,如果要批量光照贴图游戏对象,它们必须指向相同的光照贴图位置。

      5)Unity 无法将dynamic batch完全应用于使用多pass的Shader对象。

      6)几乎所有 Unity 着色器都支持Forward render中的多个光源。为了实现这一点,它们为每个光源处理一个额外的render pass。Unity 仅对第一个pass进行批处理。

它无法dynamic batch附加的每个光源的所产生的pass 进行合批处理。

七、GPU实例化(GPU Instancing)

1、定义       

当需要渲染大量相同网格、相同材质但不同位置、旋转、缩放的物体时(如森林中的树木、草地上的草),GPU 实例化可以让 GPU 只处理一次网格数据,然后使用不同的实例数据(如矩阵)来渲染多个物体。

2、使用方法:

在材质的 Inspector 面板中,勾选 Enable GPU Instancing。使用 Graphics.DrawMeshInstancedParticleSystem 等支持 GPU 实例化的组件来渲染物体。

优缺点

优点

可以极大地减少 Draw Call 数量,即使是成千上万的物体也可能只需要一个 Draw Call。对 CPU 开销很小,因为不需要合并网格。

缺点

要求物体必须使用相同的网格和材质。对 GPU 有一定的要求(需要支持 ARB_instanced_arrays 或 EXT_instanced_arrays 扩展)。

.八、使用图集 (Atlas)

1、原理

将多个小纹理打包成一个大纹理,这样可以让多个物体使用同一个材质(因为材质的纹理是同一个图集),从而可以被批处理。

2、使用方法

使用 Unity 的 Sprite Atlas 功能(适用于 2D 精灵)。对于 3D 物体,可以使用第三方工具(如 TexturePacker)来创建图集,然后在材质中使用该图集。

3、优缺点

优点

减少材质数量,从而增加批处理的可能性。减少纹理切换的开销,提高 GPU 缓存利用率。

缺点

图集的创建和管理需要一定的工作量。如果图集过大,可能会占用较多的内存和显存。

九、减少材质数量

1、原理

材质数量越多,CPU 就需要越频繁地切换材质,从而增加 Draw Call。

2、优化方法

尽可能让多个物体共享同一个材质。使用材质变体(Material Variants)或 shader 关键字(Shader Keywords)来实现材质的多样化,而不是创建多个不同的材质。避免在运行时动态创建大量材质。

十、层级细节 (LOD)

1、原理

根据物体与相机的距离,使用不同细节层次的网格模型。距离越远,使用的网格越简单。

2、使用方法

在 Unity 中,为物体添加
LOD Group
组件,并设置不同层级的网格。

3、优缺点

优点

减少远处物体的渲染开销(顶点数、三角形数减少)。间接减少 Draw Call,因为简单的网格更容易被批处理。

缺点

需要为每个物体创建多个 LOD 网格,增加了美术制作的工作量。可能会出现 LOD 切换时的视觉跳变(需要做好过渡)。

十一、遮挡剔除 (Occlusion Culling)

1、原理

通过计算相机的可视范围,只渲染那些在相机视野内且没有被其他物体遮挡的物体。

2、使用方法

在 Unity 中,启用遮挡剔除功能(
Window
->
Occlusion Culling
)。对场景进行烘焙,生成遮挡数据。

3、优缺点

优点

可以显著减少不可见物体的渲染,从而减少 Draw Call 和 GPU 开销。

缺点

烘焙过程需要一定的时间。对于动态遮挡物,遮挡剔除的效果可能不太理想。

十二、Scriptable Render Pipeline Batch(SRP Batch)

1、定义

SRP Batcher 是 Unity 提供的一种新的渲染批处理技术,它通过优化材质和渲染状态的管理,来减少 CPU 在渲染过程中的开销。

2、工作原理

传统的合批方法是减少绘制的对象。相反,SRP Batch是减少渲染的状态和执行过程。

3、使用方法

使用 Unity 的 Scriptable Render Pipeline(如 URPHDRP)。在 Project Settings -> Graphics 中,启用 SRP Batcher

4、优缺点

优点

可以显著减少 CPU 的渲染开销,尤其是在场景中有大量不同材质的物体时。对 GPU 实例化和批处理有更好的支持。

缺点

需要使用 Scriptable Render Pipeline。对材质和 Shader 有一定的要求(如必须使用 SRP Batcher 兼容的 Shader)。

在内置渲染管线中需要设置Meterial和Object CBUFFER,如果材质参数不同会被打断;但是对于SRP渲染管线,只有变体不同时才会打断合批。

5、SRP Batch规则

GameObject必须包含mesh或者 skinned mesh,它不能是粒子。Game Object没有使用MaterialPropertyBlocks设置材质信息Shader必须兼容SRP

十三、总结

        对于合批,应该实际情况做出选择,它们的合批效率从高到低依次是static > GPU instancing > Dynamic > SRP。合批的基本条件是同一个模型,并且是同一份材质信息(动态合批和SRP可以不同)。

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容