unity3d UI性能優化。

從UI(UGUI)上面的優化,我想從三個方向來分析:

drawcall的優化

動靜分離的優化

文本,圖片預選項的優化

三個優化,性能佔比,從高到底。

一. drawcall的優化

    drawcall可以通過點開Stats和Window->Frame Debugger查看具體信息
    

    在進行drawcall優化的時候,我們可以通過,移動Frame Debug的左側欄,然後觀察drawcall數量的變化,從而找到那部分ui的drawcall數量不正常。

    具體的觀察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,哪個部分處於經常變化的部分,哪個部分屬於不常變化的部分。把常變化的歸到動態區域,把不常變化的歸到靜態區域。

    以一個遊戲的主界面爲例:

    

    我把界面簡單的規劃成了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,但是如果存在性能瓶頸,我就差這麼一點了,那麼可以去優化他,是可行的。

    以上個人一點愚見,僅供參考。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章