1. 程式人生 > >Unity3D UGUI 優化:Font.CacheFontForText

Unity3D UGUI 優化:Font.CacheFontForText

前言:

最近在做專案優化的時候,有個東西非常耗時,就是Font.CacheFontForText。在真機上測出來的Profile簡直嚇人,幾十、幾百、上千毫秒都有可能。

所以這是一個必須優化的點,也是一個很那難的點。因為他的API等東西,都是寫在原生的Unity中的,外部訪問不到;而如果自己重新實現一套又太費時費力了。

正文:

1、現狀分析:

上圖可以看到,由font.cachefontfortext 引起的消耗已經有30ms以上,令人髮指,而且這還屬於在 電腦上跑,效能比較好的情況。至於手機,想想看就知道會慘不忍睹。

CacheFontForText是在UILabel在渲染時,在對應的字型的FontTexture找不到需要渲染的字元時,就會重新生成FontTexture,FontTexture尺寸越大,重新生成這張FontTexture就越耗時。

雖然不是很確定這個說法是否是正確的,但是確實和實際情況對的上。因為看Profile裡確實是從TextureRebuilt中開始呼叫,從而導致了很多Text的重繪,從而導致卡頓。其實我們再往內部檢視,其實可以看到,其耗時的原因是因為FontTexture重新繪製之後,所有依賴這個字型的Text就會把自己進行Rebuild,從而造成很多Text的重繪,造成卡頓。

2、關於Font設定的Dynamic 和Unicode

這裡說的是字型在屬性面板中的字型設定,先貼一下Unity手冊中的說明:

Import Settings for a font

看到圖中的Character屬性被設定成了Dynamic,我們也可以將其選擇為Unicode。這兩者執行起來的區別其實也沒有特別的說明,不過就我的經驗來看有兩點:

設定為Unicode時,FontSize最好設定大一些。如果像圖中設定為16,那麼在Text中,如果FontSize大於16時就會顯得模糊。而使用Dynamic則沒有這個問題,你的字型永遠是最清晰的版本。

設定為Dynamic的時候,在編輯器下(Win10)不會觸發字型重繪(Font.CacheForText)這一套操作,或者說很難觸發。有的說法是因為作業系統做了優化,但實際上並沒有官方的解釋。這裡說的不會觸發並不是說當設定成Dynamic的時候,Font.CacheForFont就一定不會被呼叫,而是說在真機上發生字型貼圖重建的節點在編輯器下不會發生。這對於優化來講是個很嚴重的問題:我明明在編輯器明明沒有,為什麼一到手機上就貼圖重建了呢?而設定為Unicode的時候,編輯器下在同一節點也會觸發CacheForText,這樣至少在除錯的時候就方便了許多。

3、解決思路

其實解決方案可以說是幾乎沒有。有一篇國外論壇上說的方法,就是一開始把所有的可能的字都交由Text取繪製一遍,之後便可不再繼續繪製了。然而現實是殘酷的:英文只有幾十個字母,加上數字和標點符號,總共也就一百來個字元而已。但是中文就不一樣了,字的數量非常多,而且都是不重複的。所以要想一次繪製完所有的字元,很困難。就算真的全繪製出來了,不但會在記憶體中產生一個很大的貼圖,而且還又很多的冗餘。

這個時候我們只有通過對文字、字型的使用來優化了。

Font類中有一個很重要的回撥方法需要監聽:

public sealed class Font : Object
{
    //……
    public static event Action<Font> textureRebuilt;
    //……
}

在UnityEngine中的Font類中,有個事件:textureRebuilt 。我們可以通過監聽這個事件,來知道哪些字型發生了重繪,從而對其進行優化。

4、優化方案

在 除錯過程中,我發現textureRebuilt的發生總是發生在這樣一種情況:某個面板上用了之前沒有使用、或雖然使用過但字數很少的字型,當他第一次開啟的時候,就發生了重繪。

例如,我的主介面等大部分都是用的宋體,但其中某個介面用的微軟雅黑。在開啟這個面板之前,雅黑這個字型基本沒用過,或者用過,但只有幾個字元。當我開啟這個面板的時候,由於需要大量的雅黑字型,此時就發生了textureRebuilt。

之後,我將這個面板中的所有字型都修改為宋體,再次開啟的時候就不再發生字型貼圖重繪了。而當我的Font設定為Unicode的時候,編輯器和手機基本上是一致的。編輯器下沒有重繪的情況,手機上也不會發生。

後記:

其實我並沒真正解決掉這個Font.CacheFontForText造成的效能問題,我只是將其規避。如果出現了某種未知情況,或者專案的需求讓我無法規避的時候,還是會產生同樣的問題。

在優化過程中,我意識到,我們不能隨意使用字型。最好的方案是,整個專案都是用同一種字型,從頭到尾。如果各個面板都是不同的字型,那麼不但很佔用空間(尤其是中文),而且還很容易發生字型重繪導致的效能問題。所以關於這一點,一定要和美術溝通好。