NGUI诡异的drawCall
看了很多关于NGUI drawCall的文章,见得比较多的一个观点是:一个 Atlas 对应一个Drawcall。
好奇心下做了个demo,两个panel中只用到一个Atlas,却产生了10个drawCall,百思不得其解。寻觅已久终于找到三篇文章:
一、http://game.ceeger.com/forum/read.php?tid=14653
[NGUI]减少NGUI 3的DrawCall数量
刚升级到NGUI3, 这下不打紧,DrawCall数由5个增长到了十七八个,想想应该不会是NGUI的问题吧。后来整理了一下,发现有两点:
1)对于同一Atlas,DrawCall数取决于Panel的数量(实际上是UIPanel这个脚本的数量)。比如说,我有两个Sprite,这两个Sprite属于同一Atlas,但是位于不同的Panel下,这时候DrawCall 数是2, NGUI 2中则是1。使用建议就是只使用一个Panel。
2)对于不同Atlas,同一Panel下的Sprite,可通过Depth调节显示层级,Z值不管用,这点跟NGUI 2中刚好相反。还有就是不同Atlas的Sprite 的Depth值尽量不要来回穿插。比如Atlas A中有两个Sprite a 和 aa,Depth分别为1,3;Atlas B中有两个Sprite b 和 bb, Depth分别为2,4, 则DrawCall 总数为4而不是2。(在NGUI 3中,你可以点击Panel ,在Inspector面板中看到每一个DrawCall的调用细节 )
简单的说就是DrawCall的数量不只跟Atlas的数量有关,还跟Atlas调用顺序有关,使用的时候最好只用一个Panel, 不同Atlas的Sprite Depth尽量不穿插。
二、http://blog.csdn.net/monzart7an/article/details/25212561
NGUI 减少drawcall
前置说明一:
Unity中的drawcall定义:
每次引擎准备数据并通知GPU的过程称为一次Draw Call。
Unity(或者说基本所有图形引擎)生成一帧画面的处理过程大致可以这样简化描述:引擎首先经过简单的可见性测试,确定摄像机可以看到的物体,然后把这些物体的顶点(包括本地位置、法线、UV等),(顶点如何组成三角形),变换(就是物体的位置、旋转、缩放、以及摄像机位置等),相关光源,纹理,渲染方式(由材质/Shader决定)等数据准备好,然后通知图形API——或者就简单地看作是通知GPU——开始绘制,GPU基于这些数据,经过一系列运算,在屏幕上画出成千上万的三角形,最终构成一幅图像。
前置说明二:
NGUI中的UIWidget的显示顺序:
每一个UIWidget的显示顺序由depth值决定,跟z轴没关系,而这个depth值是由两部分组成的,一个是UIWidget所在的UIPanel的depth和UIwidget自身的depth值进行加权计算。
并且,UIPanel的权重非常大,可以认为,UIPanel的depth大的所有UIWidget比UIPanel的depth小的所有UIWidget比最后计算的depth一定大。举个例子:
UIPanel1 depth x UIPanel2 depth y
UIWidget1 depth m UIWidget2 depth n
只要 x > y,那么不管m和n的大小,UIWidget1最后的depth一定大于UIWidget2。
减少drawcall的规则:
1、同一个UIPanel下的texture和font尽量放在同一个altals下。也表达了另外一个意思,使用同一个altals的元素尽量放在同一个UIPanel下面。
2、如果一个UIPanel下面使用了多个altals,那么尽量让使用相同altals的元素连续,尽量避免altals交叉。
规则1的前半部分好理解。后半部分,参照前面显示顺序问题可以知道。如果使用同一个altals的元素在两个不同的UIPanel下面,这就必然导致它们的drawcall分离。所以即使调整它们的depth一致,也无法合并成一个drawcall.
规则2的意思,举个例子就明白了:
同一个UIPanel下有4个UIWidget,w1,w2,w3,w4。
其中 W1和W2引用altals1。
其中 W3和W4引用altals2。
如果它们的depth顺序为 w1 : 1,w2 :2,w3 : 3,w4 : 4。
那么整个渲染需要2个drawcall,因为渲染顺序为 w1,w2,w3,w4。
而w1和w2公用一个altals,所以可以合并成一个drawcall,同理w3和w4可以合并成一个drawcall。
而如果它们的depth顺序为: w1 : 1,w2 :3,w3 : 2,w4 : 4。
那么整个渲染需要4个drawcall,因为渲染顺序为 w1,w3,w2,w4。
因为w1和w3不是公用一个altals,所以只能分开渲染。同理w3和w2,w2和w4也只能分开渲染。
三、http://bbs.9ria.com/thread-282804-1-1.html
[GUI] 源码分析NGUI的DrawCall合并原理
楼主自学Unity不久,有纰漏的地方请大神指正。正文如下:
NGUI为了减少GPU状态切换的消耗(比如切换material),把相同material的widget合并,减少DrawCall的数量。下文描述了NGUI如何对widget归类,以及减少DrawCall需要注意的地方。
归类widget的代码在UIPanel中的FillAllDrawCalls()里,代码如下
- void FillAllDrawCalls ()
- {
- for (int i = 0; i < drawCalls.size; ++i)
- UIDrawCall.Destroy(drawCalls.buffer[i]);
- drawCalls.Clear();
- Material mat = null;
- Texture tex = null;
- Shader sdr = null;
- UIDrawCall dc = null;
- if (mSortWidgets) SortWidgets();
- for (int i = 0; i < widgets.size; ++i)
- {
- UIWidget w = widgets.buffer[i];
- if (w.isVisible && w.hasVertices)
- {
- Material mt = w.material;
- Texture tx = w.mainTexture;
- Shader sd = w.shader;
- if (mat != mt || tex != tx || sdr != sd)
- {
- if (mVerts.size != 0)
- {
- SubmitDrawCall(dc);
- dc = null;
- }
- mat = mt;
- tex = tx;
- sdr = sd;
- }
- if (mat != null || sdr != null || tex != null)
- {
- if (dc == null)
- {
- dc = UIDrawCall.Create(this, mat, tex, sdr);
- dc.depthStart = w.depth;
- dc.depthEnd = dc.depthStart;
- dc.panel = this;
- }
- else
- {
- int rd = w.depth;
- if (rd < dc.depthStart) dc.depthStart = rd;
- if (rd > dc.depthEnd) dc.depthEnd = rd;
- }
- w.drawCall = dc;
- if (generateNormals) w.WriteToBuffers(mVerts, mUvs, mCols, mNorms, mTans);
- else w.WriteToBuffers(mVerts, mUvs, mCols, null, null);
- }
- }
- else w.drawCall = null;
- }
- if (mVerts.size != 0) SubmitDrawCall(dc);
- }
复制代码
算法描述如下
先把UIPanel中的Widget按depth从小到大排序,如果depth相同那按照material的ID来排序。然后遍历每个元素,把material相同的Widget归类到同一个drawCall。合并之后的结果如下图
最后生成了3个DrawCall,并按顺序提交GPU绘制。
为何要采用这个算法呢?因为NGUI的Material是透明材质,不会写入深度缓存(但是会进行深度测试,以保证与非透明物体的层次正确),我们可以看NGUI材质所使用的Unlit/Transparent Colored这个Shader,里面有一句ZWrite Off。所以widget的前后关系与z坐标是没有关系的,而是与DrawCall的绘制顺序有关。所以如果要按照上图的depth来显示widget,必然只能分成3个DrawCall,并且按顺序绘制。
其实合并drawCall的过程,正式游戏引擎“渲染队列”的职责:
NGUI诡异的drawCall的更多相关文章
- NGUI之渲染DrawCall的合并
在Unity中,每次引擎准备数据并通知GPU的过程称为一次Draw Call.Draw Call值越低,会得到更好的渲染性能. (NGUI 查看DrawCall工具(NGUI-OPEN-Draw Ca ...
- NGUI中显示DrawCall详细信息
[NGUI显示DrawCall详细信息] UIDrawCall中有个宏,SHOW_HIDDEN_OBJECTS,默认为关闭状态.将此宏打开,NGUI即会将DrawCall对象显示在Hierarchy中 ...
- NGUI优化之Drawcall
今天在运行之前的程序时,无意中发现一个简单的menu菜单页面drawcall居然达到接近30了,这个数值感觉太高了. 后网上查询关于降低drawcall的方法,发现主要有以下几点: 1.少用Panel ...
- 【Unity3D游戏开发】NGUI之DrawCall数量 (四)
看了非常多关于NGUI drawCall的文章.见得比較多的一个观点是:一个 Atlas 相应一个Drawcall. 但事实上NGUI内部有自己的一套对DrawCall的处理规则. 相关的规则有: 1 ...
- NGUI 渲染流程深入研究 (UIDrawCall UIGeometry UIPanel UIWidget)
上图是一个简要的NGUI的图形工作流程,UIGeometry被UIWidget实例化之后,通过UIWidget的子类,也就是UISprit,UILabel等,在OnFill()函数里算出所需的Geom ...
- Unity3D面试问题
注意,是问题,不是笔试题哦.这些是我最近面试北京各公司总结的一些被问到的还算典型的问题.跟大家分享一下.答案是我自己的,不保证标准和完整. 哎,公司年底开人,又校招一群便宜的小鬼……桑死心了……好在找 ...
- NGUI 减少drawcall规则
前置说明一: Unity中的drawcall定义: 每次引擎准备数据并通知GPU的过程称为一次Draw Call. Unity(或者说基本所有图形引擎)生成一帧画面的处理过程大致可以这样简化描述:引擎 ...
- (转)最近一个项目中关于NGUI部分的总结(深度和drawCall)
在自己最近的一个项目中,软件的界面部分使用了NGUI来进行制作.在制作过程中,遇到了一些问题,也获取了一些经验,总结下来,作为日后的积累. 1.NGUI图集的使用. 此次是第一个自己正儿八经的制作完整 ...
- NGUI 降低drawcall
前置说明一: Unity中的drawcall定义: 每次引擎准备数据并通知GPU的过程称为一次Draw Call. Unity(或者说基本全部图形引擎)生成一帧画面的处理过程大致能够这样简化描写叙述: ...
随机推荐
- BZOJ 2286: [Sdoi2011]消耗战 虚树 树形dp 动态规划 dfs序
https://www.lydsy.com/JudgeOnline/problem.php?id=2286 wa了两次因为lca犯了zz错误 这道题如果不多次询问的话就是裸dp. 一棵树上多次询问,且 ...
- POJ 2778 DNA Sequence(AC自动机+矩阵)
[题目链接] http://poj.org/problem?id=2778 [题目大意] 给出一些字符串,求不包含这些字符串的长度为n的字符串的数量 [题解] 我们将所有串插入自动机计算match,对 ...
- 在Hexo中渲染MathJax数学公式
最近学机器学习涉及很多的数学公式,公式如果用截图显示,会比较low而且不方便.因此需要对Hexo做些配置,支持公式渲染.同时文末整理了各种公式的书写心得,比如矩阵.大小括号.手动编号.上下角标和多行对 ...
- 升级Tornado到4后weibo oauth登录不了
把 Tornado 升级到4后,发现正常运行的微博登录不可以了. 原因是4已经移除 RequestHandler.async_callback and WebSocketHandler.async_c ...
- Python编码规则
1. 命名规则 1.1 变量名.包名.模块名 变量名通常有字母.数字和下划线组成,且首字母必须是字母或下划线,并且不能使用python的保留字:包名.模块名通常用小写字母 1.2 类名.对象名 类名首 ...
- python开发_csv(Comma Separated Values)_逗号分隔值_常用导入导出格式_完整版_博主推荐
## 最近出了一趟差,是从20号去的,今天回来...# 就把最近学习的python内容给大家分享一下...#''' 在python中,CSV(Comma Separated Values),从字面上面 ...
- Codeforces Round #350 (Div. 2) D1. Magic Powder - 1 二分
D1. Magic Powder - 1 题目连接: http://www.codeforces.com/contest/670/problem/D1 Description This problem ...
- PAT甲级1111. Online Map
PAT甲级1111. Online Map 题意: 输入我们当前的位置和目的地,一个在线地图可以推荐几条路径.现在你的工作是向你的用户推荐两条路径:一条是最短的,另一条是最快的.确保任何请求存在路径. ...
- ThinkPHP使用纯真IP获取物理地址时中文乱码问题
今天在用ThinkPHP通过纯真IP获取地址时,发现输出结果中文乱码,如图: 经查发现ThinkPHP的IpLocation.class.php类文件中说明:“由于使用UTF8编码 如果使用纯真IP地 ...
- JS实现《黑客帝国》落地字母背景
JS实现<黑客帝国>落地字母背景.这个特别有意思,主要是通过设置字符相关属性.控制循环字母距离顶部的高度值,来达到字母不断循环下落的功能. 恩,还有加上一个随机机制,出现各种大小 各个位置 ...