super1 发表于 2021-4-16 09:12

十五:Unity UGUI 点击性能优化

最近在做性能优化,我们希望能力尽力做到平滑60帧,在战斗逻辑方面,已经做了不少优化。其他方面,即使是边边角角的地方,也不能放过,所以,这次分享一点个人认为有通用参考价值的优化点,并且做起来也不难。
在测试过程中,发现在进行点击UI操作的时候,EventSystem.Update()是一个很大的消耗,在我们的游戏中,安卓上大概在2ms左右,如果希望跑60帧,每帧只有16ms的空间,所以,2ms也是需要慎重对待的。
后续找到三篇文章,也谈到这个问题,罗列如下:


我主要采用了第一,第二两篇文章的优化方法,这里只谈谈和参考文章不同的几点处理,希望大家在看下面内容前,可以先看下上面的参考文章。
第一:文章有提到:unity中,我们即使不勾选raycastTarget,还是会进入raycast列表的计算。可以通过继承的方式,override一些方法,来处理掉这块的消耗。
第二篇参考文章截图
在项目中后期,我不希望通过继承Image或Text的方式,来替换掉prefab中已经使用的Image等控件,这带来很多的修改维护成本。
所以,我的思路是:当创建UI界面的prefab的时候,获取到prefab中所有的Graphic,在UI从隐藏到显示的时候,将所有没有勾选raycastTarget的Graphic,从判定列表中移除,代码简单处理如下:
private Graphic[] _allGraphics;

protected void Awake()
{
   _allGraphics = gameObject.GetComponentsInChildren<Graphic>();
}

protected void onShow()
{
   for (int i = 0; i < _allGraphics.Length; i++)
   {
         if (_allGraphics.raycastTarget == false)
         {
            GraphicRegistry.UnregisterGraphicForCanvas(_currCanvas, _allGraphics);
          }
      }
}


第二:根据隐藏界面的不同方式,注意将隐藏的界面从raycast判定中去除
当前隐藏UI界面,有几种思路:一种是设置active 为false,一种是将UI位置移动到可见范围外。
如果使用set active的方式,就不必额外担心,当Graphic OnDisable的时候,ugui会处理掉这块事情(可以看Graphic 的源码)。
如果是使用移动到可见范围外的方式来隐藏UI界面,在可见范围外的UI,也会参与raycast的计算,就需要自己处理这块的逻辑。例如在OnHide的时候,将所有Graphic 移除raycast判定,类似如下处理:
protected void onHide()
{
   for (int i = 0; i < _allGraphics.Length; i++)
   {
         GraphicRegistry.UnregisterGraphicForCanvas(_currCanvas, _allGraphics);
      }
} 这里,要根据自己的UI系统怎样组织,注意处理显示隐藏界面时候的不同处理。
如果你的UI是使用每个UI界面一个Canvas的方式,那么,只需要在隐藏和显示的时候,调整当前界面对应的GraphicRaycaster 的enable状态即可,不再赘述。


最后说下优化的效果,在unity editor下,优化前是这样:
优化前
优化后是这样:
优化后
可见,同样的操作,性能消耗,在editor下从6ms,减少到约2ms。Graphic.get_depth()的调用次数大幅度减少。
在安卓真机测试中,从2ms,减少到0.5ms,减少了1.5ms,算是个不错的优化效果,需要做的事情也不多。
我还做了一些相关的小优化,但是是基于现在项目的UI组织方式,不具有通用性,就不提了。大家如果想要尝试这个优化,注意要领会这个优化的思路本身,根据自己的项目具体处理。在一些UI相对复杂的项目,相信会有比较好的效果。
最后,需要感谢前面提到的三篇参考文章的作者,做了非常细致的工作。

Baste 发表于 2021-4-16 09:18

受教了

ainatipen 发表于 2021-4-16 09:22

通过看UE4源码的Slate处理点击的思路来看,我觉得你可以试试将屏幕分块,每块维护着当前和屏幕块有重叠的控件。

unityloverz 发表于 2021-4-16 09:29

谢谢

HuldaGnodim 发表于 2021-4-16 09:39

不知道代价有多大,有空看看

johnsoncodehk 发表于 2021-4-16 09:41

其实你拿到UGUI源码,直接修改GraphicRegistry.RegisterGraphicForCanvas函数,然后里面判断 if (!g.raycastTarget) return; 就好了

JamesB 发表于 2021-4-16 09:47

我写了,不希望通过改源代码的方式来优化。如果改源码,当然可以做更多优化

BlaXuan 发表于 2021-4-16 09:47

不太信任GetComponentsInChildren的性能

Zephus 发表于 2021-4-16 09:53

这个优化是开关ui的一次性调用,不是每帧。

ChuanXin 发表于 2021-4-16 09:57

可以可以
页: [1] 2
查看完整版本: 十五:Unity UGUI 点击性能优化