近期有同学面试,被问到这样一道面试题:
”说说UGUI的动静分离是怎么一回事?”
关于这个优化有一些误区,容易让开发者陷入一个极端。我们先分析关于UGUI 合批优化的问题,最后给这个面试题一个参考回答。
对惹,这里有一个游戏开发交流小组,希望大家可以点击进来一起交流一下开发经验呀!
Unity UGUI 到底采用的是哪种合批技术?
Drawcall合批技术,我们一般是有动态合批,静态合批,GPU Instancing合批。对于GUI部分,游戏引擎>游戏引擎合批一般采用哪些技术呢?这个取决于游戏引擎>游戏引擎的实现,比如Unity UGUI采用的是静态合批,预先把Mesh等合并好,而Cocos Creator 引擎采用的是通用的动态合批。为什么不使用GPU Instancing合批呢?主要可能考虑有几个原因:半透明,九宫格,tiledmap等相关的处理,这类GPU Instancing不适合处理。不是所有的设备与显卡支持GPU Instancing, 兼容性不如动态合批or静态合批。所以大部分游戏引擎>游戏引擎的UI,要么采用静态合批,要么采用动态合批。”静态合批与动态合批”都会导致一个问题,就是要重新计算与合并Mesh。”静态合批”合批的一个好处就是合并完后如果内部的UI元素没有位置等信息没有修改,就不用重新计算,渲染的时候直接把合并好的数据提交渲染就可以了。”动态合批”是遍历每个可以合批的UI元素,将数据合并后一起提交给GPU渲染。动态合批更灵活,更通用。
Unity UGUI 合批的开销分析
UGUI 是基于Canvas来进行合并计算的。这样会导致以下几个问题:
1: 不同Cavans的UI元素,是无法合批渲染,无法使用同一个drawcall;
2: 每次合并的时候,会合并计算Canvas下所有的UI元素, 具体的算法流程为:
Step1: 一开始计算合并Cavans下所有的UI元素;
Step2: 每帧提交合并后的结果给GPU渲染;
Step3: 当某个UI元素改变以后,先计算某个UI元素改变后的数据,再结合其它UI元素,重新合并到一起。
3: 每次UI元素的位置等相关信息改变,都会引发合并计算;
4: “不动物体”的合并计算开销是最小的,如果Cavans下所有的UI元素一旦创建都不再改变,那么合并计算这块只要计算一次,性能最好。
5: 当Cavans下有不断变化的物体时,每次都会有合并计算,此时不动的物体少,那么最后合并的时候物体的数据就少。
由上面的分析,很多人就得到一个结论: 动静分离,将不变的物体放一个canvas,变化的物体放一个canvas下,优化合并时候的开销。进而有人推导出来: “每个界面一个Cavans。然后面试时,被奉为经典,导致大家回答每个界面我们都做一个Canvas。减少Mesh合并的开销。”
每个UI界面都做Canvas到底有没有必要?
假设有两个界面,界面A(50个UI元素),界面B(50个UI元素), 他们可以合批。假设界面A中的所有UI元素都不变化,界面B中的每个UI元素的位置在不断的改变,我们来分别讨论:"界面A,界面B共用一个Canvas与界面A,界面B分开两个Cavans在合并上的开销"。
情况1: 界面A,界面B共用一个Cavans;
Step1: 计算界面A中每个UI节点元素转换后的位置等信息, 计算A50个元素,计算一次;
Step2: 计算界面B中每个UI节点元素转换后的位置等信息,计算B50个元素,由于变化,每次都计算
Step3: 将A的50个元素信息(只计算一次) + B的50个元素信息,合并成100大的mesh,一起提交;
情况2;界面A,界面B共用2个Cavavns;
Step1: 计算界面A中单个UI节点元素转换后的位置等信息, 计算A50个,计算一次;
Step2: 合并界面A中的所有的UI节点元素数据,合并计算一次,将结果每次提交给GPU渲染;
Step3: 计算界面B中单个UI节点元素转后的位置等信息,计算B50个,每次改变都计算;
Step3: 将B50个信息合并到一起,提交给GPU进行渲染,每次都要合并,将结果提交给GPU渲染;
仔细比对,我们发现,情况1优于情况2的是,A,B可以一起提交,节约drawcall。情况2优于情况1的是最后合并时,不用copy A的50个元素信息的数据,其它合并计算并没有太大的差别。
情况1比情况2能节约一个drawcall, 情况2比情况1在合并的时候,少copy 合并50个数据。
经上面分析,基于多Canvas的”动静分离”会打乱合批,能节省的是”合并时不变的元素的数据copy”。
总结: 没有必要每个UI界面都做一个Cavans, 一般我们做开发的时候,常规的游戏UI界面做一个Cavans, 大规模的弹出式滚动列表可以考虑做一个Cavans。游戏元素,如2D游戏中角色,2D/3D游戏中的玩家昵称,角色血条等,可以做一个Cavans。一般项目中2~3个Cavans就可以了。还是要把重点放在UI的drawcall优化上。
参考回答: 说说UGUI的动静分离是怎么一回事?
最后给出这个面试题的参考回答:
Unity UGUI 会基于Canvas,将能合并的UI元素,计算合并到一起,然后再提交给GPU渲染来节约Drawcall,在这个过程中,如果某个UI元素改变了,就会引发一次合并计算。”动静分离”一般指的是把那些不经常动的UI与经常动的2D元素分成不同的Cavans,来减少合并时候的开销。这个通常叫做”动静分离”。我们在开发项目的时候,会把经常变化的游戏元素(2D游戏角色,玩家昵称,玩家血条等)做到一个Cavans下。把通常的游戏操作UI界面做一个Cavans下,对于那些UI内容非常多的如”任务滚动列表”等,我们也会考虑单独做一个Cavans,然后持续监测UI性能即可。有人说每个界面做一个Cavans,个人觉得没有必要。如果UI部分有性能问题,再具体问题具体分析即可。
更多教学视频
Unity3Dwww.bycwedu.com/promotion_channels/2146264125