【Unity3D游戏开发】NGUI之DrawCall数量 (四)
看了非常多关于NGUI drawCall的文章。见得比較多的一个观点是:一个 Atlas 相应一个Drawcall。
但事实上NGUI内部有自己的一套对DrawCall的处理规则。
相关的规则有:
1.Atlas图集数量有关
2.Atlas图集的调用顺序(绘制顺序)有关
3.和UIPanel的数量有关
一、降低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://game.ceeger.com/forum/read.php?tid=14653
二、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://blog.csdn.net/monzart7an/article/details/25212561
三、源代码分析NGUI的DrawCall合并原理
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。而且按顺序绘制。
參考文章:http://bbs.9ria.com/thread-282804-1-1.html
【Unity3D游戏开发】NGUI之DrawCall数量 (四)的更多相关文章
- (转)Unity3D游戏开发 NGUI之渐变加载到100%的Loading场景进度条
NGUI 现有的进度条存在的问题: 进度条跳跃式前进,加载到90%后卡住,突然进入下一个场景.接下来就是解决这个问题. 背景 通常游戏的主场景包含的资源较多,这会导致加载场景的时间较长.为了避免这个问 ...
- Unity3D游戏开发从零单排(四) - 制作一个iOS游戏
提要 此篇是一个国外教程的翻译,尽管有点老,可是适合新手入门. 自己去写代码.debug,布置场景,能够收获到非常多.游戏邦上已经有前面两部分的译文,这里翻译的是游戏的最后一个部分. 欢迎回来 在第一 ...
- [Unity3D]Unity3D游戏开发之跑酷游戏项目解说
大家好,我是秦元培.我參加了CSDN2014博客之星的评选,欢迎大家为我投票,同一时候希望在新的一年里大家能继续支持我的博客. 大家晚上好.我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.c ...
- Unity3D游戏开发初探—2.初步了解3D模型基础
一.什么是3D模型? 1.1 3D模型概述 简而言之,3D模型就是三维的.立体的模型,D是英文Dimensions的缩写. 3D模型也可以说是用3Ds MAX建造的立体模型,包括各种建筑.人物.植被. ...
- [Unity3D]Unity3D游戏开发之飞机大战项目解说
大家好,我是秦元培,欢迎大家继续关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei. 首先感谢大家对我博客的关注,今天我想和大家分享的是一个飞机大战的项目.这是一个比較综合的 ...
- [Unity3D]Unity3D游戏开发之异步记载场景并实现进度条读取效果
大家好,我是秦元培.欢迎大家关注我的博客,我的博客地址是:blog.csdn.net/qinyuanpei.终于在各种无语的论文作业中解脱了,所以立即抓紧时间来这里更新博客.博主本来计划在Unity3 ...
- [Unity3D]Unity3D游戏开发之伤害数值显示
大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei.众所周知,在RPG游戏策划中最为重要的一个环节是数值策划.数值策划是一个关于游戏平衡方面的概念 ...
- [Unity3D]Unity3D游戏开发之怪物AI
大家好.欢迎大家关注由我为大家带来的Unity3D游戏开发系列文章,我的博客地址为:http://blog.csdn.net/qinyuanpei. 在上一篇文章中,我们基本上实现了一个 ...
- 内置3D对象-Unity3D游戏开发培训
内置3D对象-Unity3D游戏开发培训 作者:Jesai 2018-02-12 19:21:58 五大面板: -Hierachy:当前场景中的物体 图 1-1 -Project:项目中的所有资源 图 ...
随机推荐
- (回溯法)和为n的所有不增正整数和式分解算法
题目: 利用递归算法输出正整数和为n的所有不增的正整数和式.例如当n=5时,不增的和式如下: 5=5 5=4+1 5=3+2 5=3+1+1 5=2+2+1 5=2+1+1+1 5=1+1+1+1+1 ...
- ArcGIS Pro体验04——菜单栏
对菜单栏进行熟悉一下: 1.地图菜单 剪切板(Clipboard):剪切(Cut).复制(Copy).粘贴(Paste),这些不用说了,在ArcMap中是放在"编辑"菜单下面的.当 ...
- 绕过Web授权和认证之篡改HTTP请求
一.什么是HTTP请求 超文本传输协议(HTTP)提供了多种请求方法来与web服务器沟通.当然,大多数方法的初衷是帮助开发者在开发或调试过程中部署和测试HTTP应用.如果服务器配置不当,这些请求方法可 ...
- 算法笔记_123:蓝桥杯第七届省赛(Java语言B组部分习题)试题解答
目录 1 凑算式 2 方格填数 3 四平方和 1 凑算式 凑算式 B DEF A + --- + ------- = 10 C GHI (如果显示有问题,可以参见[图1.jpg]) 这个算式中A ...
- 使用fiddler来抓包
使用fiddler来抓包 Sniffer,wireshark,WinNetCap.WinSock Expert,SpyNet 都是当前流行的抓包工具 需要先做一些简单的准备工作: 一台带有无线网卡的P ...
- Ubuntu vim+ ctags(包括系统函数) + taglist 配置
阅读大型代码,我们常常须要打开非常多的代码文件,搜索各种定义.windows下用惯了ide的朋友.转战Linux的时候可能会认为非常难受,找不到合适的阅读工具. 事实上万能的vim就能够实现. 以下介 ...
- sed备忘
sed 是一种在线编辑器,它一次处理一行内容.处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送 ...
- C#基础蛋疼到爆的Byte类型表数范围之网兜毛衣见解……
事实上写这篇对Byte类型表数范围的文章,真的是蛋疼+蛋疼+蛋疼,每每看到Byte表数范围这一块.都对-128如此的陌生与迷茫.操蛋的Byte,操蛋的人生-- 熊孩子出场:Byte 恶作剧结果:表数范 ...
- 转载【微信小程序】:微信小程序滚动Tab选项卡:左右可滑动切换(仿某宝)
1.本文转载至:http://blog.csdn.net/sophie_u/article/details/71745125 2.效果: 3.最终效果如上.问题: 1).tab标题总共8个,所以一屏无 ...
- PHP-多域名单点登陆方案
1.只是二级域名不同(比如a.xx.com, b.xx.com) 利用cookie, 设置domain为".xx.com"即可 2.多个本域名都不相同(比如www.a.com, w ...