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)带有如MeshRender、TrailRender、LineRender、ParticleSystem、SpriteRender组件的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.DrawMeshInstanced 或 ParticleSystem 等支持 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(如 URP、HDRP)。在 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可以不同)。



















暂无评论内容