《Unity3D高级编程之进阶主程》第四章,UI(七) - UI优化(一)

前文回顾 UI(一)

    对NGUI和UGUI进行了比较,讲述了如何选择UI系统作为项目的UI框架。

前文回顾 UI(二)

    UGUI的原理,以及组件使用详解。

前文回顾 UI(三)

    UGUI源码中输入事件模块源码剖析。

前文回顾 UI(四)

    UGUI渲染核心源码剖析

前文回顾 UI(六)

    如何在游戏项目中架构UI框架。

这篇我们来聊聊,优化UI的几种方法,UI动静分离,拆分过大的UI,UI预加载。

===

① UI动静分离。

什么是UI动静分离?

动就是左右上下移动,或放大缩小频率比较高的UI,静就是静止不动的,或者说动的比较少的UI。

我们在做项目中,避免不了一些UI会动,从左边移到右边,或从上面移到下面,或者一个小范围的移动,这些一直在动的,或者说有时会动的UI就属于行动中的UI。

那么为什么要将他们分离开来呢?

UGUI 和 NGUI一样,都是用模型构建UI画面的,在构建后都做了合并Mesh的有优化操作,不合并会导致无数drawcall进而导致CPU,GPU消耗过大,游戏画面卡顿。

合并操作是好的,但问题是UI元素一动就需要重新合并,而不需要重新构建的内容也一并合进去了,导致原来合并Mesh的好事变坏事。

因此要将行动的UI元素和静态不动的UI元素分离开来,让合并的范围缩小,只合并那些会动的UI元素,因为他们重绘的频率比较高,而那些基本不动的UI元素就不让它们参与重新合并Mesh的操作了。

那么如何分离他们呢?

UGUI 和 NGUI都有自己的重绘合并节点,UGUI是Canvas,NGUI是UIPanel。

以重绘的合并节点为关键点,进行拆分。把会动的UI元素放入专门为它们准备的合并节点上,而将静止不动的UI留在原来的合并节点上。

这样一来,当会动的UI元素来回移动缩放的时候,不再重构静态部分的UI了,毕竟静态的UI元素占UI的大多数,而动态的UI元素只是小部分,减少了不少的CPU在重绘和合并时的消耗。

② 拆分过大的UI。

为什么要拆分过大的UI?

项目的制作过程是个比较长的过程,在这个过程中UI的大小会随着项目时间的积累而不断扩大。

很多时候我们总是莫名其妙的感觉,‘怎么这个UI界面,前段时间还好好的,现在打开会变得如何缓慢呢?!‘。

问题就在于,随着项目的推进,UI经手的人越来越多,添加的内容也越来越多,有的甚至一个Prefab里,装着2-3个界面,只是在显示时隐藏了其他的几个而已。最后导致,UI过大,实例化,初始化,过慢的问题。所以我们要想办法拆分这些,过大的UI界面。

如何拆分?

首先,把隐藏的UI界面拆分出来,成为独立运作的界面,只在需要是调用实例化。

其次,如果界面内容还是很多,我们可以把2次显示的内容拆出来。

什么是2次内容?打个比方,一个界面打开时会显示一些内容(例如动画),完毕后或者点击后才能看到另外的内容。

这后来出现的内容视为2次显示内容,可以考虑拆分出来成为独立的界面,需要时再加载。

注意权衡加载速度与内存,过大的UI固然加载缓慢内存消耗大,但拆分成小个体时,如果小个体频繁加载和销毁,也同样会消耗过多CPU。

③ UI预加载。

为什么要进行UI的预加载?

我们在UI实例化时,需要将Prefab实例化到场景中,这期间还会有Mesh的合并,组件的初始化,渲染初始化,图片的加载,界面逻辑的初始化等程序调用,消耗掉了很多CPU。

这导致了在我们打开某个界面时,出现卡顿的现象,就是CPU消耗过重的表现。如何优化呢?

上面讲的拆分UI是一个方面,但只能用在一些冗余比较大的界面上,而一些容易比较小,难以拆分的UI界面,就很难用这个方法达到优化到顺畅的效果。

甚至有的UI界面即使拆分后,任然会消耗很多CPU,出现卡顿的现象。如何优化呢?

加载图片的数量是无法减少的,不能因为要优化我就把图给删了,这样不太妥当,偏离优化而不伤害项目的本质。

UI上的元素也是不能减少的,也不能因为要优化,把UI元素给去掉,影响原本的项目。

初始化程序也是必不可少的,虽然从某种程度上说初始化程序里也有糟糕的程序,但这部分我们总是可以在Unity3D分析器Profile找出原因,所以可以先放下不管。

从分析上来看,我们已经不能从内部优化UI的实例化问题了,这导致了我们需要通过外部的方法进行优化,也就是我们需要对UI进行预加载。

如何进行UI预加载?

第一种方法,

    最直接的方法,在游戏开始前加载UI资源但不实例化,比如把Resources.Load(“ui”)这句放在进游戏画面之前。这样当点击按钮后,弹出UI界面时就少了一点加载资源的时间,把CPU消耗重心放在了实例化和初始化上。

第二种方法,

    在第一种方法的基础上,打开界面时CPU还是消耗太严重,那么就将UI实例化和初始化也提前到游戏开始前。

    但在实例化和初始化后,对UI界面进行了隐藏,当需要他出现时,再显示出来,而不是重新实例化,当关闭时,也同样只是隐藏,而不是销毁。

    这样一来在打开和关闭时,只消耗了少量CPU在展示和隐藏上。

第三种方法,

    Unity3D 5.x的新功能Preload,在平台设置里,有这个功能,可以把需要预加载的Prefab加入到列表中去。

    它会将这些Prefab在进入APP或者说打开应用展示LOGO界面时进行预加载。

    它在整个APP初始化时,预加载了指定的Prefab,CPU消耗在了前置的碎片时间,很难让人感觉到加载的停顿感,整体效果不错。

最后,我要提醒一下,所有的预加载,都会出现另一个问题,CPU集中消耗带来的卡顿。

我们预加载并没有削减CPU,CPU消耗的总量是不变的,需要加载的图片数是不变的,实例化的面片数是不变的,以及初始化程序需要消耗的时间是不变的,所有消耗都是不变的。

我们只是把它们这些消耗分离了或者说提前了,然后拆分到各个时间碎片里去,让人感觉不到很大的CPU消耗,或者说卡顿感。

但如果你将这些预加载,集中在某个位置,比如全部集中在游戏开始前,或者进度条的某个位置,也同样会有强烈的卡顿感,因为CPU在这个点进行了集中的消耗。

下篇将继续聊聊 UI 优化。

感谢您的耐心阅读

Thanks for your reading

  • 版权申明

    本文为博主原创文章,未经允许不得转载:

    《Unity3D高级编程之进阶主程》第四章,UI(七) - UI优化(一)

    Copyright attention

    Please don't reprint without authorize.

  • 微信公众号