UGUI DrawCall合批细节(转)

UGUI DrawCall合批细节(一)——合批的规则
UGUI DrawCall合批细节(二)——Mask影响合批
UGUI DrawCall合批细节(三)——RectMask2D与Mask的区别及选择
UGUI避坑指南

转发大佬的文章,讲得比较清楚了,也方便自己学习。


一、合批的规则

UGUI在合批之前,会根据ui的Depth、MatID 、ImgID、RendererOrder进行排序,之后对相邻的UI进行检测,判断ImgID和MatID是否相同,如果相同则可以进行合批处理,如果这两个UI的MatID和ImgID都相同,但是不连续,中间有其他不同MatID或ImgID的UI则会打断合批。

Depht排序:
1.先筛选掉Depht为-1的值,这部分默认不渲染;
2.接着判断是否该元素底部是否有物体,如果没有则负责Depth为0,如果盖住物体(这块是通过Mesh进行判断,判断Mesh是否相交)则等于底部盖住的UI元素中Depth最大的值+1;
3.如果两个相邻元素通过了合批测试,则这两个相邻元素的深度值相等;
4.深度排序之后,就会根据matID进行排序,如果材质相同则对ImgID进行排序,如果也相同,那会根据inspection面板上的RendererOrder,最后真正进行UI的合批。

如图示:

hierrchy面板顺序如图

drawCall如下:

可以看到是5个,因为文本打断了Depth的合批。

在Debug Frame里我们可以清楚的看到他有3个DrawMesh

那只需要将hierrchy的顺序修改到最后,我们看会发生什么。

hierrchy面板顺序如图:

drawCall如下:

降为了4,代表三张image进行了合批。

用FrameDebug也可以清楚的看到优化是成功的。

特殊情况:

下面我们在看一个特殊的案例

请注意面板上的顺序,按我们理解的情况看,他应该排序后的顺序是:文本,图片,图片,之后因为两个图片的材质一致所以能够进行合批。

但是通过frameDebug我们发现,实际上顺序却是:图片,文本,图片这样的顺序,那这是为什么呢,我们更进一步,通过Profiler的UI的modules来看具体的细节

给出的原因是贴图不同,目前两个图片的贴图都是Nil,那我们尝试修改两张图片的贴图

之后我们再观察会发现

这里的顺序就是我们预期的顺序文本,图片,图片了,那为什么会发现这种问题呢,是因为在默认情况下,排序了depth之后,这两个层级相同,就会比较matID,image和text的默认材质都是ui defult,mat也一致,在比较TextureID时,img为nil比默认的Text的TextureID小,所以排序在了text前,但是替换了贴图后,图片的TextureID大于Text的TextureID,下面的显示就达到了预期的效果。

二、Mask影响合批

在UGUI的开发中我们常谈少用Mask,但是为什么少用,用了Mask又会影响什么呢,今天我们就来简单说说。

(一)被mask的元素为什么不能和外部元素合批

首先我们先来聊聊mask的实现,我们简单搭建一个测试场景

会发现多了一个mask会多出3个drawCall,我们查看Mask的源码

他在StencilMaterial.Add的时候为这个maskUI增加了一个新的材质,导致了mask内的物体无法和外部同样材质的物体合批,这是其一,其二是mask会进行两次pass,第一步是对在模板缓冲中的值进行赋值,将要显示的部分缓存值设置为1,不显示的部分设置为0,在第二个pass绘制时对模板缓冲值为0的部分进行剔除,所以这两个pass也会带来两个drawcall的生成。所以添加一个mask最起码会增加3个drawcall。并且了解原理我们会发现,其实虽然是不显示但是被mask剔除的部分还是存在的,只是不会进行绘制而已,这也会影响到我们后面会说的,层叠下异常增长的drawcall,这个我们后面来详解。

(二) 不同mask之间的合批

不同的mask之间是可以合批的,在我们上一章《UGUI DrawCall合批细节(一)》中讲解过,相同材质和贴图的两个UI物件是能够进行合批的,虽然Mask会对原来的材质进行替换,添加一个新的材质,但是新添加的材质和新添加的材质之间就支持合批,所以我们现在简单添加两个mask查看drawCall效果:

一个Mask的情况下:

两个Mask的情况下:

我们会发现drawCall数量并没有增加,证明了我们的推论是正确的,但是这里有一个例外情况,也是我们接下来要论述的第三点也是最容易被人忽略的点。

(三)被mask的物体只是不被绘制,依旧会影响合批计算

我们先看我现在mask的物体被剔除的部分:

可以发现在下部分的红色方块被剔除了,那用第二节的理论验证了mask之间会进行合批的,但是是绝对的吗,并不是,我们看一个情况。

同样的物体我们把他移动到上一个mask的最底部我们发现合批并没有出现,而是又增长了3个drawCall,这是为什么?

细节就在这里被遮罩剔除的区域,实际上也是会参与合批计算的,当这两个mask不重叠的时候,他们depth相同,mat相同,可以进行合批,但是当他们重叠时,因为被剔除的部分参与了运算,发现depth不同并且mat也不同,就无法进行合批,会增加3个Drawcall,这就是很多时候项目里明明没重叠但是却多了很多drawCall的情况。

三、RectMask2D与Mask的区别及选择

RectMask2D

那我们同比分析一下UI上常用的第二个Mask组件RectMask2D,等同于Mask的测试场景,我们测试单个mask2D开启和关闭对drawCall的影响。

开启前:

开启后:

我们可以发现DrawCall只增加了一个,因为内部的元素无法和外部进行合批增加了一个drawCall,并且内部的元素自己能够进行合批。而且和Mask不同的是,mask2D并不会产生两额外的pass增加两个drawcall的消耗。这是为什么呢?

查看rectMask2D的源码我们可以发现,他并没有替换材质的过程,没有用到模板缓冲的实现方式,而是通过了canvasRender里面进行了ClipRect的剔除,这样相比于Mask会带来以下不同:

(一)RectMask2D之间无法进行合批

我们复制一份mask2D对象可以发现,drawCall增加了1

查看差异的理由可以发现是因为不同的裁剪区域,所以我们能知道,RectMask2D之间内部的元素是无法进行合批的,这也是和Mask不同的部分

(二)被mask隐藏的物体不会参与合批计算

相比于mask不同,我们这里添加了RectMsk2D,虽然进行了重叠但是我们发现draw并没有增加,并且做一个测试,将同一个mask下的材质换成不同的贴图后,将一个mask移出区域,

会发现根本不会计算移除出区域的图片的drawCall,所以这是和Mask的第二个区别。

(三)RectMask2DUI组件上挂载的Image可以参与外部的合批

我们做一个简单的测试:

可以发现在添加和移除Image组件时,drawcall的数量没有增加,因为新添加的img和外部的黄色方块的材质一致,进行了合批。而Mask组件没有Image组件的话都无法生效,这是和mask的第三个区别。

总结:

所以到底我们项目是使用Mask还是使用RectMask2D呢?在我看来这是应用场景的选择问题,当界面只有一个mask需要使用的时候,RectMask2D无疑是最优解,只会带来一个drawCall的增加,如果是多个Mask并且互相是可以合批的,那无疑Mask更适合在那种情景下使用,但是使用的时候也需要注意被剔除区域的层叠问题。

四、UGUI避坑指南

想到啥写啥吧,就随笔类似记录知识点一样一个个说,有空的话再编辑或者再开新帖具体讲讲某些点,都是UGUI优化的建议:
(1)优化填充率,裁减掉无用的区域,镂空等;
(2)Mask的使用以及选择,或者用自用Mask,这块原理我在UGUI的合批里讲过,可以翻一翻我前面博客这里不再复述;
(3)少用unity自带的outline和shadow,会大量增加顶点和面数,比如outline,他实现原理是复制了四份文本然后做不同角度的便宜,模拟描边,要不就用自己实现的(挖坑待填);
(4)操作全屏UI时建议将场景相机移走或者关闭,降低渲染面数,因为就算是被全屏UI遮挡住了,实际上后面的场景还是被渲染的占用资源;
(5)如果非特殊需求没必要使用CanvasPixedPerfect,因为比如在scrollView时,滑动视图时一直会导致不断重绘产生性能损耗;
(6)不需要接受点击时间的物件将RayCastTarget关掉减少事件响应,从底层看是因为UGUI的RayCastTarget的响应是从数组中遍历检测是否和用户的点击区域响应,所以能够缩减数组大小自然能够缩减遍历次数;
(7)UI动静分离,因为如果了解过Unity的UGUI源码就能发现Batch building 的过程,Canvas 会将其 ui 元素生成的 mesh 组合并生成合适的绘制命令给 Unity 渲染系统。并且过程的结果会被缓存并重用,直到 Canvas 重新被标记为脏。这会在组合的网格发生变化时发生。Canvas 会根据子节点里带有 Canvas Renderer 组件的 ui 来生成 网格,但是不包括 Sub-Canvas 的子节点,也就是说每个 Canvas 单独负责自身的 Batch building。Batch building 的过程会对根据深度、重叠测试、材质等对各个 Mesh 进行排序、分组、合并,这个过程是多线程的,在移动端(核心少)与桌面端(核心多)会呈现相当大的差异。Canvas下的某个元素进行变化时都会导致同一个Canvas下的所有元素都进行网格重建,这样会导致某些静态部分的网格被不同重绘导致额外性能损耗。而常用的拆分canvas有两种,一种是在同一个根节点下new一个动态Canvas,类似图示:

这种用法的缺点是层级关系不好调控,当静态Canvas下的某些物体需要显示在动态canvas下的物件上时就很麻烦。

所以我推荐第二种方式子Canvas的方式来实现这点。

类似上图在子物体上挂在subCanvas,这样的好处是它与其父节点是隔离的,Sub-Canvas 的 rebuild 不会逼迫父节点重建几何,反之亦然,不过还是存在一些边界情况。比如父节点变化导致子节点大小变化。但是Canvas会打断合批,所以比如只是拖拽某个组件的操作,可以在开始拖动时挂载subcanvas,结束拖动移除canvas,这样的做法能够保证物体的合批顺序,同时兼顾了动静分离。

(7)对于UI上常用的改变颜色的操作,不要使用Image组件上的Color属性改变颜色,这样会导致整个Canvas的重建,可以新建个材质,设置材质给Image的Material通过修改材质的颜色来达到同样效果

(8)对于界面上常用的组件隐藏,别使用SetActive来控制显影,有两种方式,一种是通过设置物体上的CullTransparentMesh并且控制物体透明度进行剔除,这个一般用于单个ui,如果是多个UI要不显示的话通过设置canvasGroups的Alpha控制显影。

(9)Text的组件的BestFit非必要别开,因为这样开启这个会不断生成各种尺寸的字号字体图集,增加不必要开销。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,776评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,527评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,361评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,430评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,511评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,544评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,561评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,315评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,763评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,070评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,235评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,911评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,554评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,173评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,424评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,106评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,103评论 2 352

推荐阅读更多精彩内容