【Unity优化】DrawCall与Batch

一、渲染一帧步骤

0-1、剔除:摄像机视锥体剔除、代码删除/隐藏Mesh

0-2、从硬盘HDD中加载纹理、Mesh到内存RAM,再将需要渲染的加载到VRAM[1]。

1、设置全局 Render State(Unity中对应SetpassCall),包含:顶点/片元着色器、纹理、材质、光照、透明度等

2、CPU发送一个DrawCall给GPU,指向VRAM中的一个Mesh(不包括材质,这是上一步的工作)。

3、GPU根据当前 Render State,以及CPU指向的顶点数据,通过代码生成像素并显示到屏幕。

如果后续Mesh使用相同的 Render State,那么重复2、3步骤;否则需要执行一次1步骤。

步骤3称为管线Pipeline。管线中从开始到结束,比较关键的模块有:顶点着色器、光栅化、片元着色器。顶点和片元着色器是可编程的,即常说的Shader。

[1] RAM、VRAM分别存储什么:https://www.reddit.com/r/gamedev/comments/camqq0/whats_stored_in_ram_and_vram/

https://forums.unrealengine.com/development-discussion/rendering/1651940-i-want-to-learn-more-about-how-vram-is-used-and-texture-object-optimizations

(1)VRAM:GPU内存仅存储当前帧(DC)需要的资源,比如:纹理、mesh、shader、framebuffer、constant buffer、以及其他渲染场景所需的通用数据。处理完当前的DC后,就会清除数据,准备下次DC。

(2)RAM:RAM包含可执行代码、音频、游戏数据。一般不包含纹理、mesh这些已经在VRAM中的资源(CPU从HDD中读到RAM,传给VRAM,然后从RAM中清除。然而如果需要在CPU中检测碰撞,mesh信息就需要保留)。

(3)RAM、VRAM:动画、物体变换一般同时存在。通常在CPU中每帧更新,然后复制到VRAM中渲染。

二、优化概述

Render State、DrawCall属于CPU的工作,都比较耗时。优化方向:降低它们的执行次数。

减少 Render State:减少材质的种类

减少 DrawCall:不同的Mesh尽量使用同一个材质;对同种材质的Mesh做合批处理;使用GPU Instancing

其他优化:避免OverDraw(避免使用透明,错误示范:为了实现四角阴影,使用一张全屏图片)

三、优化细节

合批分为动态、静态。

【静态合批】:将相同材质的Mesh合并成一个大Mesh。

优点:降低DC,且只需要执行一次,可以是不同Mesh;

缺点:占用内存,不能部分剔除。

适合:静态大Mesh。

【动态合批】:实时地将相同材质的Mesh合并成一个大Mesh。

优点:降低DC,可以是不同Mesh,可以部分剔除。

缺点:每帧都要执行,消耗CPU,且占用内存。如果该步骤消耗的CPU,大于降低DC所带来的的提升,则反而影响性能。限制较多(非负缩放、没有光照贴图或使用相同的光照贴图位置、material单pass、不能接受实时阴影)

适用:动态的大量小Mesh。

【GPU Instancing】CPU只发送一次Mesh给GPU,GPU自己去复制实例化。为了让Mesh有不同的状态,甚至播放动画,CPU需要同时提供一份额外数据(比如变换矩阵)。

优点:解放CPU。

缺点:需要是相同的Mesh,对平台和API有要求(Windows要求DirectX11以上、OpenGL Core 4.1+/ES 3.0+)

适用:大量相同的Mesh,比如植被

四、容易出错的地方

1、修改Render.material导致不能动态合批:

(1)Unity提供了两个获取Material的方法接口,分别是material及sharedMaterial。当对物体的material进行任何修改时,Unity会对Render里Materials列表第一个预设的Material进行实例化,并将返回实例。Unity这么做的目的是不影响其他物体,而仅仅修改这个实例。

(2)如果调用sharedMaterial,Unity就不会帮我们实例化,直接返回原本的材质球。但是会让所有使用该sharedMaterial的模型响应相同的修改。如果这不是你想要的,可以创建两个材质球,根据不同的情况替换材质。

Ref: [**记一次Dynamic Batching不生效的爬坑实例分析Unity]**

2、动态合并的限制是单个模型900顶点:

Unity文档中所说的动态合并的顶点限制是900,指的是单个模型,而不是合批的模型总和。合批的模型总和上限是65535[1]。同理,如果Shader使用了顶点坐标、法线、单个UV,那么限制是300个顶点;如果使用了顶点坐标、法线、UV0、UV1和切线,则限制是180个顶点。这两个限制针对的也是单个模型。

[1] https://forum.unity.com/threads/unity-5-3-static-batching-not-batch-draw-calls.372625/

posted @ 2020-07-21 22:27  何三思  阅读(1283)  评论(0编辑  收藏  举报