图形引擎渲染画面的过程

Unity(或者说基本所有图形引擎)生成一帧画面的处理过程大致可以这样简化描述:

1. 可见性测试

1. 引擎首先经过简单的可见性测试,确定摄像机可以看到的物体

2. 准备好物体的数据

2. 然后把这些物体的顶点(包括本地位置、法线、UV等),索引(顶点如何组成三角形),变换(就是物体的位置、旋转、缩放、以及摄像机位置等),相关光源,纹理,渲染方式(由材质/Shader决定)等数据准备好

3. 通知图形API开始绘制

3. 然后通知图形API——或者就简单地看作是通知GPU——开始绘制,GPU基于这些数据,经过一系列运算,在屏幕上画出成千上万的三角形,最终构成一幅图像。

什么是Draw Call

在Unity中,每次引擎准备数据并通知GPU的过程称为一次Draw Call。

这一过程是逐个物体进行的,对于每个物体,不止GPU的渲染,引擎重新设置材质/Shader也是一项非常耗时的操作。

因此每帧的Draw Call次数是一项非常重要的性能指标,对于iOS来说应尽量控制在20次以内,这个值可以在编辑器的Statistic窗口看到。

Draw Call Batching 技术

Unity内置了Draw Call Batching技术,从名字就可以看出,它的主要目标就是在一次Draw Call中批量处理多个物体。

只要物体的变换和材质相同,GPU就可以按完全相同的方式进行处理,即可以把它们放在一个Draw Call中。

Draw Call Batching的核心

Draw Call Batching技术的核心就是在可见性测试之后,检查所有要绘制的物体的材质,把相同材质的分为一组(一个Batch),然后把它们组合成一个物体(统一变换),这样就可以在一个Draw Call中处理多个物体了(实际上是组合后的一个物体)。

Draw Call Batching的缺陷

但Draw Call Batching存在一个缺陷,就是它需要把一个Batch中的所有物体组合到一起,相当于创建了一个与这些物体加起来一样大的物体。

与此同时就需要分配相应大小的内存。这不仅会消耗更多内存,还需要消耗CPU时间。

特别是对于移动的物体,每一帧都得重新进行组合,

但对于静止不动的物体来说,只需要进行一次组合,之后就可以一直使用,效率要高得多。

这就需要进行一些权衡,否则得不偿失。

Dynamic Batching和Static Batching

Unity提供了Dynamic Batching和Static Batching两种方式。

Dynamic Batching

Dynamic Batching是完全自动进行的,不需要也无法进行任何干预。

对于顶点数在300以内的可移动物体,只要使用相同的材质,就会组成Batch

Static Batching

Static Batching则需要把静止的物体标记为Static,然后无论大小,都会组成Batch。

如前文所说,Static Batching显然比Dynamic Batching要高效得多,于是,Static Batching功能是收费的……

高效利用Draw Call Batching

要有效利用Draw Call Batching,有以下注意点:

1. 首先是尽量减少场景中使用的材质数量,即尽量共享材质,对于仅纹理不同的材质可以把纹理组合到一张更大的纹理中(称为Texture Atlasing)。

2. 然后是把不会移动的物体标记为Static。此外还可以通过CombineChildren脚本(Standard Assets/Scripts/Unity Scripts/CombineChildren)手动把物体组合在一起,但这个脚本会影响可见性测试,因为组合在一起的物体始终会被看作一个物体,从而会增加GPU要处理的几何体数量,因此要小心使用。

3. 对于复杂的静态场景,还可以考虑自行设计遮挡剔除算法,减少可见的物体数量同时也可以减少Draw Call。

总之,理解Draw Call和Draw Call Batching原理,根据场景特点设计相应的方案来尽量减少Draw Call次数才是王道,其它方面亦然。

参考资料: http://ravenw.com/blog/2011/10/14/unity-optimization-of-draw-call/#sthash.eWSmEU7K.dpuf

理解二:DrawCall

在Unity查看Draw Call

开发游戏时,一定被时时提醒要减少 Draw Call,当然Unity也不例外,打开Game 窗口裡的 Stats,可以看到 Draw Call 与 Batched 的数字。

Draw Call 定义

但到底甚麼是 Draw Call?影响的效能是来自 CPU?还是 GPU?
首先,让我们定义何為 “Draw Call”:

“一个 Draw Call,等于呼叫一次 DrawIndexedPrimitive (DX) or glDrawElements (OGL),等于一个 Batch”

摸过 DirectX 或 OpenGL 的人来说,对 DrawIndexedPrimitiveglDrawElements这 API 一定不陌生。

当我们准备好资料 (通常为三角面的顶点资料) 要 GPU 划出来时,一定得调用这个函数。

举例说明

换句话说,如果在画面上有一张 “" 椅子、一张 “" 桌子,那理论上就会有两个 Draw Call。

有看到特別指出 “木" 与 “铁" 吗?这代表两物件是使用不同材质球或者不同的 Shader。

在 DirectX 或 OpenGL 里,对不同物件指定不同贴图或不同 Shader 的描述,就会需要呼叫两次Draw Call。

举例代码

SetShader( “Diffuse" );
SetTexture( “铁" );
DrawPrimitive( DeskVertexBuffer ); SetShader( “VertexLight" );
SetTexture( “木" );
DrawPrimitive( ChairVertexBuffer );

每次对 Shader 的更改或者贴图的更改,基本上就是对 Rendering Pipeline 的設定做修改,所以需要不同的 Draw Call 來完成物件的绘制。

現在了解为什麼 UNITY 官方文件里,老是要你尽量使用同样材质球,以减少 Draw Call 数量了吧!

Batch(Draw Call的另一种称呼)

在来谈到 Batch,其实也是 Draw Call 的另一种称呼。

你可以理解成每一次的 Draw Call 会产生一个 Batch,而 Batch 里装的是物件顶点资料。

Batch 由 CPU 通过 “驱动程式” 将顶点资料送往 GPU,GPU接手后将物件画在画面上。

由此可知,越多 Draw Call,CPU 就越忙碌。这下更清楚知道 Draw Call 数量所影响的是 CPU 效能而非 GPU。

NVIDIA 在 GDC 曾提出,25K batchs/sec 会吃满 1GHz 的 CPU,100% 的使用率。所以他们推出了一条公式,来预估游戏中大概可以 Run 多少个 Batch:

举个例子:如果你的目标是游戏跑30FPS、使用2GHz的CPU、20%的工作量发給Draw Call來使用,那你每秒可以有多少Draw Call呢?

333 Batchs/Frame = 25K * 2 * (0.2/30)

那既然 Batch 是个箱子,里头裝着物件的顶点资料,再依据我們上面的描述,

那将同样材质和Shader 的物件,可以合併成一個 Batch 送往 GPU,这样就是最省事的方法喽?Yes!就是這樣沒錯!

UNITY 在 Player Setting 里的两个功能选项 Static Batching 与 Dynamic Batching。功能描述如下:

Static Batching

Static Batching 是将标明为 Static 的静态物件,如果在使用相同材质球的条件下,UNITY 会自动帮你把这两个物件合併成一个 Batch,送往 GPU 来处理。

这功能对效能上非常的有帮助,所以是需要付费才有的

Dynamic Batching

Dynamic Batching 是在物件小于300面的条件下(不论物件是否不静态或动态),在使用相同材质球下,UNITY就会自动帮你合併成一个 Batch 送往 GPU 来处理。

参考资料:http://www.unityin.com/2012/09/draw-call-batch-%E5%82%BB%E5%82%BB%E5%88%86%E4%B8%8D%E6%B8%85%E6%A5%9A/

Unity的DrawCall的更多相关文章

  1. Unity优化----drawcall系列

    本文由博主(国宝大熊猫)原创,转载请注明出处:http://www.cnblogs.com/xsln/p/5151951.html 知识普及:      *Drawcall影响的是CPU的效率.因为d ...

  2. [Unity优化] Unity CPU性能优化

    前段时间本人转战unity手游,由于作者(Chwen)之前参与端游开发,有些端游的经验可以直接移植到手游,比如项目框架架构.代码设计.部分性能分析,而对于移动终端而言,CPU.内存.显卡甚至电池等硬件 ...

  3. Unity优化之减少Drawcall

    简单来说,Drawcall就是屏幕渲染一次所需要的开销,为了较少消耗,提高性能,一般有以下几种方法. 一: 批处理 1.动态批处理 如果动态物体共用着相同的材质,那么Unity会自动对这些物体进行批处 ...

  4. 如何降低Unity程序的Drawcall

    [如何降低Unity程序的Drawcall] Unity can combine a number of objects at runtime and draws them together with ...

  5. unity drawcall测试

    unity引擎影响drawcall的元素(使用Quad和Cube对比测试) 1.相机的background(没有渲染元素区域的颜色),4Verts.2Tris.1SetPass calls:      ...

  6. (转)Unity优化之减少Drawcall

    转载:http://www.jianshu.com/p/061e67308e5f Unity GUI(uGUI)使用心得与性能总结 背景和目的 小哈接触Unity3D也有一段时间了,项目组在UI解决方 ...

  7. Unity性能优化-DrawCall

    1. DrawCall是啥?其实就是对底层图形程序(比如:OpenGL ES)接口的调用,以在屏幕上画出东西.所以,是谁去调用这些接口呢?CPU.比如有上千个物体,每一个的渲染都需要去调用一次底层接口 ...

  8. unity panel删除drawcall失败导致的残留影像

    ngui panel 被隐藏或者删除的时候调用ondisable,清空drawcall,如果这个操作是在ontriggerenter等物理操作中就会删除不掉导致留下残影 解决方式 : 讲这些操转移到协 ...

  9. 转 unity 优化

    最近研究U3D开发,个人认为,精通一种新的技术,最快最好的方法就是看它的document,而且个人习惯不喜欢看中文的资料,原汁原味的东西是最正确的,一翻译过来很多东西就都不那么准确了.于是通读了uni ...

随机推荐

  1. JavaScript基础系列(变量与类型)

    以下内容将JavaScript简称为JS 打开本文时不管你是零基础的初学者还是其他语言的老兵,我都想说程序语言的基础支撑起了整个网络世界,不把这些基础学透之后稍复杂的内容会让你寸步难行. 现在先给编程 ...

  2. JavaScript学习笔记3之 数组 & arguments(参数对象)& 数字和字符串转换 & innerText/innerHTML & 鼠标事件

    一.Array数组 1.数组初始化(Array属于对象类型) /*关于数组的初始化*/ //1.创建 Array 对象--方法1: var arr1=[]; arr1[0]='aa';//给数组元素赋 ...

  3. putty保持不掉线

    putty连接linux,一会就掉线了,然后再重新输入,比较麻烦. 参考http://www.putty.ws/putty-lianjie这篇文章解决. 如图,30表示每隔30秒putty会发一个空的 ...

  4. Angular JS | Closure | Google Web Toolkit | Dart | Polymer 概要汇集

    AngularJS | Closure | Google Web Toolkit | Dart | Polymer GWT https://code.google.com/p/google-web-t ...

  5. Android studio修改Logcat颜色

    Android studio默认的Logcat配色不利于阅读,我们可以修改自定义自己的颜色配置

  6. Android 生成xml文件

    生成XML文件备份短信,其格式为: <?xml version="1.0" encoding="UTF-8" standalone="true& ...

  7. iOS 图片加载导致内存警告

    虽然UITableView和UICollectionView都有cell复用机制,但是如果利用SDWebImage加载的图片本身过大且cell复用池中的个数比较多(cell的Size越小,复用池中的c ...

  8. CoreData数据库迁移的操作

    CoreData数据库迁移操作步骤,操作是基于Xcode7. 1.添加新的数据库.选中当前数据库版本:Editor->Add Model Verson,创建一个新的数据库版本. 2.Comman ...

  9. iOS-点击推送消息跳转处理

    当用户通过点击通知消息进入应用时 - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDi ...

  10. IOS开发之代理的设计小技巧

    1.关于代理对象的设计小技巧 在设计一个类,需要通过代理和协议来从外部获取需要的动态的数据.那么在这里设计使用代理会有两种方法. <第一种方法> 也是比较常见的: 在你设计的类中,声明一个 ...