• 【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/

  • 相关阅读:
    双链表( 初始化,建立,插入,查找,删除 )
    单链表(程序员宝典)
    单链表(建立、插入、删除、打印)
    Hive- 表
    Spark- 性能优化
    Spark- Checkpoint原理剖析
    Spark- 优化后的 shuffle 操作原理剖析
    Spark- Spark普通Shuffle操作的原理剖析
    Spark- Spark内核架构原理和Spark架构深度剖析
    Spark- Spark基本工作原理
  • 原文地址:https://www.cnblogs.com/hearthstone/p/13357821.html
Copyright © 2020-2023  润新知