Unity3D :关于UGUI的网格重建、动静分离

时间:2019-03-18
本文章向大家介绍Unity3D :关于UGUI的网格重建、动静分离,主要包括Unity3D :关于UGUI的网格重建、动静分离使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

前言:

无论是网上的攻略还是以前的经验来说,都说UGUI需要进行动静分离。也就是说同一个界面下的UI,可活动的元素放在一个Canvas下,不可活动的元素放在另一个Canvas下。虽然两个Canvas打断了合批,但是却减少了网格的重建时间,总体上是有优化的。

究其原因,是因为在同一个Canvas下的某个元素发生变化时,同一Canvas下的所有元素都会进行网格重建(ReBatch)。而静态的元素在逻辑上是不需要重建的,因为他们都没变过,所以需要分开。

但是我在实际进行测试的时候(5.6.6)却发现在Profile中没有体现:

创建了200个图片,其中100个在活动,另外100个静止。无论是怎么划分Canvas,其Rebuild次数始终为200(每一个Image的重建需要调用2次Rebuild)。简单地说,你动静分离也好,不分离也好,都是变化几个元素重建几次,而且从CPU时间来看也没有任何区别。那是不是说动静分离没什么用了?反正分不分都一样。

这不是和之前的经验不一样吗?每次面试的时候都有答动静分离……

 

正文:

后来在网上咨询了各路大佬,最终了解到了其中的原因。下面谈谈我自己的理解(可能有误,知道大概意思就好)。

参考:

《Fill-rate, Canvases and input》:https://unity3d.com/cn/learn/tutorials/topics/best-practices/fill-rate-canvases-and-input?playlist=30089&tdsourcetag=s_pcqq_aiomsg

《Making the UI Backend Faster》:https://blogs.unity3d.com/cn/2015/09/07/making-the-ui-backend-faster/?_ga=2.205691671.503332160.1539763005-1817454406.1519290009

《关于Unity中的UGUI优化,你可能遇到这些问题》:https://blog.uwa4d.com/archives/QA_UGUI-1.html

 

1、网格重建的过程:

UGUI的网格重建分为2部分,一个是ReBatch,一个是ReBuild。

当你的Canvas下的一个元素发生变化了,就会重新绘制当前Canvas下的所有的可绘制元素,不管其是否变化过。重新计算其图片、位置、缩放、文本等等元素。这一部分就是ReBatch。之前的动静分离的工作都是在优化ReBatch,而在之前的Unity(5.2 以前)都还能在Profile里面看到 Canvas.BuildBatch这个方法的性能消耗。然而这之后的Unity便不能看到他的消耗,只能看到他的一个几乎不耗时的工作分配(JobAlloc.Grow),至少在5.6.6是这样的。

而Rebuild在ReBatch之后,是每个UI元素自己的操作。比如A元素变了,而B元素没有变,那么A元素就自己改一下自己就好了。至于哪些元素需要Rebuild,则在 Canvas.BuildBatch 里面就计算好了。

 

2、5.2以后对Canvas.BuildBatch做的优化

在5.2之后对 Canvas.BuildBatch 流程做了优化,一部分是算法的优化,另一部分是流程的优化。

算法不讨论。流程方面,在CPU超过一个核心的情况下,Unity将Canvas.BuildBatch流程放在在主线程之外,使用多线程进行计算。由于不再占用主线程的时间,因此BuildBatch的消耗就可以忽略不计了。由于在另外的线程里面,所以只要那个线程没有超负荷,我们在主线程看到的Profile怎么看都不会有差。

根据文章 《Fill-rate, Canvases and input》的介绍来看,反正是没有必要建立那么多的Canvas,几个画布就OK了:

In Unity 5.2, the batching code was substantially rewritten, and is considerably more performant compared to Unity 4.6, 5.0 and 5.1. Further, on devices with more than 1 core, the Unity UI system will move most of the processing to worker threads. In general, Unity 5.2 reduces the need for aggressively splitting a UI into dozens of Sub-canvases. Many UIs on mobile devices can now be made performant with as few as two or three Canvases.

 

3、Canvas仍可用于Text和Image的分离

虽然动静分离的意义不大了,但是Text和Image的分离的意义还是很大的。经测试,多个Text和多个Image分处于两个独立的节点,在绘制是并不一定是先绘制完Image,再绘制Text。具体情况比较复杂,可能是先绘制一两个Image,然后一两个Text,然后继续绘制。个中原理不甚清楚,但是这样的后果就会打断合批。

最为方便的操作方式是将Image和Text各自的父节点各挂载一个Canvas,这样就能实现强制分组。至少在Canvas下的同一字体的Text就一定是在一批中了。

 

总结:

新版的Unity(5.2+)将 Canvas.BuildBatch 放在了其他线程进行操作,而现在的手机一般都是多核(骁龙650就是6核了),电脑也是,所以动静分离的优化不会对帧率造成影响。过多的Canvas反而会打断合批,增加DrawCall,其实也是需要取舍的。不过即便在别的线程里面操作,也是要进行运算的,运算多一些CPU发热手机就会降频,这也是很麻烦的事情。

只能说动静分离之类的操作在新的版本下没有那么有必要,但是也不是没有没有用,有点鸡肋。

不过在测试的时候,如果使用了上千个变化的UI元素和上千个不变的元素进行测试,还是能发现动静分离的差别的。其实这个原因猜测是用于计算Canvas.BuildBatch的线程耗时已经超过了主线程,造成掉帧。不过在一边的游戏中,是不存在这么多UI元素的,所以也不用担心。