Unity游戏开发入门征服Unity3dUnity3D游戏开发

Unity优化之NGUI篇

2017-03-10  本文已影响832人  bYsdTd

最近在做项目的优化工作,测试发现UI的开销占到了一半以上,所以先从他下手。

源码分析

NGUI有几个重要的类,UIPanel,UIWidget,UIDrawCall。其中UIPanel用一个静态链表保存游戏里的所有UIPanel,每个UIPanel在列表里的顺序是由depth决定的,注意这里是静态链表,并没有父子关系。

public int depth
{
    get
    {
        return mDepth;
    }
    set
    {
        if (mDepth != value)
        {
            mDepth = value;
#if UNITY_EDITOR
            NGUITools.SetDirty(this);
#endif
            list.Sort(CompareFunc);
        }
    }
}

每一个UIPanel用一个list保存所有的UIWidget, 顺序是先按照depth排,depth相同再按照材质排


public void SortWidgets ()
{
    mSortWidgets = false;
    widgets.Sort(UIWidget.PanelCompareFunc);
}
    
static public int PanelCompareFunc (UIWidget left, UIWidget right)
{
    if (left.mDepth < right.mDepth) return -1;
    if (left.mDepth > right.mDepth) return 1;

    Material leftMat = left.material;
    Material rightMat = right.material;

    if (leftMat == rightMat) return 0;
    if (leftMat != null) return -1;
    if (rightMat != null) return 1;

    return (leftMat.GetInstanceID() < rightMat.GetInstanceID()) ? -1 : 1;
}

每个UIPanel管理自己的Drawcall

public List<UIDrawCall> drawCalls = new List<UIDrawCall>();

大概流程就是每一帧每个UIPanel去更新所有属于他的UIWidget,什么算属于,其实就是每个UIWidget去他的父节点里一直向上找,第一个找到的就是它属于的UIPanel

static public UIPanel Find (Transform trans, bool createIfMissing, int layer)
{
    UIPanel panel = null;

    while (panel == null && trans != null)
    {
        panel = trans.GetComponent<UIPanel>();
        if (panel != null) return panel;
        if (trans.parent == null) break;
        trans = trans.parent;
    }
    return createIfMissing ? NGUITools.CreateUI(trans, false, layer) : null;
}

更新UIWidget的过程, 就是准备UIDrawCall的过程,先去现有的DrawCall里面去找,如果找到材质相同,并且贴图相同,shader也相同的就认为可以放到一个DrawCall里,否则的话,就只能重建当前这个UIPanel的所有DrawCall

public UIDrawCall FindDrawCall (UIWidget w)
{
    Material mat = w.material;
    Texture tex = w.mainTexture;
    int depth = w.depth;

    for (int i = 0; i < drawCalls.Count; ++i)
    {
        UIDrawCall dc = drawCalls[i];
        int dcStart = (i == 0) ? int.MinValue : drawCalls[i - 1].depthEnd + 1;
        int dcEnd = (i + 1 == drawCalls.Count) ? int.MaxValue : drawCalls[i + 1].depthStart - 1;

        if (dcStart <= depth && dcEnd >= depth)
        {
            if (dc.baseMaterial == mat && dc.mainTexture == tex && w.shader == dc.shader)
            {
                if (w.isVisible)
                {
                    w.drawCall = dc;
                    if (w.hasVertices) dc.isDirty = true;
                    return dc;
                }
            }
            else mRebuild = true;
            return null;
        }
    }
    mRebuild = true;
    return null;
}


void UpdateSelf ()
{
    mUpdateTime = RealTime.time;

    UpdateTransformMatrix();
    UpdateLayers();
    UpdateWidgets();

    if (mRebuild)
    {
        mRebuild = false;
        FillAllDrawCalls();
    }
    else
    {
        
    ......

优化策略

to be continued

专栏文章全都转移到知乎专栏了,欢迎关注,交流。
知乎专栏-程序员的自我修养

上一篇下一篇

猜你喜欢

热点阅读