欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

unity3d UI性能优化。

程序员文章站 2024-03-17 17:10:22
...

从UI(UGUI)上面的优化,我想从三个方向来分析:

drawcall的优化

动静分离的优化

文本,图片预选项的优化

三个优化,性能占比,从高到底。

一. drawcall的优化

    drawcall可以通过点开Stats和Window->Frame Debugger查看具体信息
    
unity3d UI性能优化。
    在进行drawcall优化的时候,我们可以通过,移动Frame Debug的左侧栏,然后观察drawcall数量的变化,从而找到那部分ui的drawcall数量不正常。

unity3d UI性能优化。

    具体的观察drawcall的方式讲了,下面来讲一下几个容易造成drawcall数量偏大的原因和优化drawcall的小tips

    1.mask的多次使用。

    mask对于drawcall的影响应该是所以组件里面最大的。每存在一个mask,就把mask以内和以外的UI分割成两个“世界”,依次计算两个“世界”的drawcall,然后再相加。原因是mask以内和以外的UI不能通过unity3d一次渲染(batch)。所以在使用mask的时候要仔细思考,能不用就不用,实在要用可以考虑用带通道的图片代替mask的遮罩功能。

    2.图集整理不规范。

    影响drawcall数量的根本是batch(批处理数),而batch是根本一个一个图集来进行批处理的。简单来说,两张image重叠在一起,当两张image的sprite是一个图集里的时候,这两张image就是一个batch;当不是一个图集的时候,两张image就变成了两个batch。所以在处理图集的时候,通常做法是,常用图片放在一个共有图集,然后独立界面的图片放在一个图集,一个UI最好控制在2-3个图集。

    3.图文交叉。

    unity3dUGUI的batch规则除了依赖于图集之外,还依赖于组件关系,当2张图片(同一图集),1个文字进行重叠时,处理不好会发生一些drawcall的多余。比如:image->image->text,这样的话,drawcall就是两个,但是当:image->text->image的时候,就算两张image的sprite是一个图集的,这样的drawcall都会有3个。所以尽量不要出现image->text->image,图文交叉的情况。根据原因2,也有个小tips,当存在两个图集的三张image的时候,也尽量不要出现image1->image2->image1这样的操作。

    4.UI层级的深度。

    在不必要的情况下,我们尽量减少UI层级的深度,在UGUI中Hierarchy面板,节点的的深度,表现的就是UI层级的深度,我们UI中有N层,N越大越靠前,会遮住后面的组件。当深度越深,不处在同一层级的UI就越多,drawcall就会越大。

二. 动静分离的优化

    当我们在制作UI的时候,我们应该考虑到整个UI,哪个部分处于经常变化的部分,哪个部分属于不常变化的部分。把常变化的归到动态区域,把不常变化的归到静态区域。

    以一个游戏的主界面为例:

    unity3d UI性能优化。

    我把界面简单的规划成了4个区域:

    1.上方按钮区域

    2.右方按钮区域

    3.技能区域

    4.人物头像及任务区域

    如果按照简单的动静分离原因:1.2区域是不常变化的,我们放在一个节点以下;3.4区域是常变化的,几乎每一秒都在变化,我们放在一个节点以下。这样就可以达到动静分离的效果。

    动静分离,可以减少UIMesh动态更新,在某些比较复杂,常驻的界面可以这样优化。小的界面就没必要了,因为不必要的节点有可能会造成drawcall的增加的。

三. 文本,图片预选项的优化

    这部分主要有两个可以优化的点。效果可能没有前面两种优化大,但是积少成多,在项目后期,有优化瓶颈的时候,也是非常有必要的。

    1.image和text组件的Raycast Target属性

    在组件不需要射线检测的时候,我们可以尽可能的把射线检测去掉,在运行的时候,就可以减少不必要的性能开销。

    这里给一段小代码,在创建image和text的时候,就可以去掉Raycast Target

using UnityEngine;
using UnityEditor;
using UnityEngine.UI;

public class CancelImgandTxtRay
{
    [MenuItem("GameObject/UI/Image WithoutRay", false, 10)]
    static void CreatImage(MenuCommand menuCommand)
    {
        EditorApplication.ExecuteMenuItem("GameObject/UI/Image");
        GameObject go = Selection.activeGameObject;
        GameObjectUtility.SetParentAndAlign(go, menuCommand.context as GameObject);
        go.GetComponent<Image>().raycastTarget = false;
    }

    [MenuItem("GameObject/UI/Text WithoutRay", false, 10)]
    static void CreatText(MenuCommand menuCommand)
    {
        EditorApplication.ExecuteMenuItem("GameObject/UI/Text");
        GameObject go = Selection.activeGameObject;
        GameObjectUtility.SetParentAndAlign(go, menuCommand.context as GameObject);
        go.GetComponent<Text>().raycastTarget = false;
    }
}

    2.text组件的Rich Text属性

    当text组件勾选了Rich Text的时候,其实每次文本显示都会先判断一下是否拥有这个属性,然后做正则匹配,如果不勾选的话,其实还是有一些优化的。但是这个优化点其实是最小的,不必要的话,其实没必要优化这个,事实证明,在通常情况下如果我们不勾选,但是后期又要对text进行富文本的操作,容易引出一些不必要的bug。

    第一条和第二条优化是必须的,带来的性能提升是巨大的。但是当不存在性能瓶颈的时候,不建议去优化第三条,性能的提升不是很大,容易引出不必要的bug,但是如果存在性能瓶颈,我就差这么一点了,那么可以去优化他,是可行的。

    以上个人一点愚见,仅供参考。