UGUI的原理和優(yōu)化

UGUI介紹:

? ? IMGUI : 是Unity自帶得到古老UI系統(tǒng)。

????NGUI : 是最流行的第三方UI插件。

? ? FairyGUI : 是跨平臺的UI系統(tǒng)。(小游戲居多)

? ? UGUI : 是官方版本。

? ? UI Element : 是最新版本的UI系統(tǒng)。(Unity2019版)

那么這么多的GUI,為什么選擇UGUI呢? 因為團隊最擅長(重點),官方支持,流行趨勢,多線程支持(UI重建)

UGUI開源地址 :?https://bitbucket.org/Unity-Technologies/ui

UI基礎(chǔ)控件 :?

Text 文本 , Image 圖片 , RawImage 原圖片 , Mask 遮罩 , Effects 特殊效果(陰影,描邊等)

UI交互控件 :?

Button 按鈕 , Toggle 開關(guān) , Slider 滑動條 , Scrollbar 滾動條? , Input Field 輸入框 , Scroll Rect 滾動視圖 , Dropdown 下拉框

UI布局控件 :?

Horizontal Layout Group 水平布局 , Vertical Layout Group 垂直布局 , Grid Layout Group 網(wǎng)格布局

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 相機和畫布

Canvas : 畫布是所有UI元素的父元素,就像優(yōu)化的畫布一樣,控制者對UI元素的渲染。也就是說所有UI控件都需要作為Canvas對象的子對象才可以被渲染出來。

渲染順序 : 畫布上的UI元素按照排列順序渲染。位于上方的元素先被渲染,下方的元素后被渲染。對于嵌套的結(jié)構(gòu),先渲染父類,在渲染子類。

渲染模式: Canvas有三種渲染模式 :?

Screen Space - Overlay:不需要指定UI相機,渲染會覆蓋整個畫面,永遠(yuǎn)在屏幕的最上面。

Screen Space - Camera:需要指定UI相機,畫布會被放置在相機前,通過該相機渲染。

World Space:把畫布當(dāng)成普通的3D對象放置在世界坐標(biāo)系中,畫布可以自由移動旋轉(zhuǎn)。

適配策略 :?

UI Scale Model :?

Scale With Screen Size:UI元素的位置和大小是根據(jù)指定的標(biāo)準(zhǔn)分辨率來設(shè)置。(該模式在不同分辨率的設(shè)備上會自動適配)

Constant Pixel Size:UI元素的位置和尺寸是由畫面上的像素單位來設(shè)置。

Constant Physical Size:UI元素的位置和尺寸可以使用物理單位(厘米,英寸等)來設(shè)置。

Screen Match Mode:當(dāng)屏幕分辨率與標(biāo)準(zhǔn)分辨率的寬高比例不一致的時候,畫布如何縮放

Match Width or Height:按照標(biāo)準(zhǔn)分辨率的寬度或高度來縮放畫布。

Expand:擴展畫布,畫布的寬和高同時擴展,畫布的尺寸不會低于標(biāo)準(zhǔn)分辨率。在此模式下會保證標(biāo)準(zhǔn)分辨率下的東西能夠全部顯示出來。

Shrink:收縮畫布,畫布的寬和高同時收縮,畫布的尺寸不會高于標(biāo)準(zhǔn)分辨率。在此模式下不會留黑邊但是會導(dǎo)致顯示不完全。

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 布局系統(tǒng)

RectTransform 組件:錨點,軸心,坐標(biāo)值,旋轉(zhuǎn)值,縮放值。

Blueprint模式:未采用旋轉(zhuǎn)或縮放的矩形框。

RawEditor模式:在編輯pivot時,pivot會始終保持在UI內(nèi)的相對位置,UI跟隨pivot的位置移動。

錨點:UI元素矩形框的位置和大小,以錨點在父物體的矩形框內(nèi)的位置作為自身偏移和拉伸的參考。

錨點在編輯視圖里是四個小三角形(錨點控制柄),這四個小三角組成里了一個錨框。

錨框的范圍不能超過父類的矩形框,錨框的四個控制柄可以聚合到同一個位置。

為了便于理解界面里的數(shù)值,我們給錨點定義了倆種形態(tài):錨點形態(tài)和錨框形態(tài)

錨點形態(tài):物體的大小不會隨著父物體的大小變化而變化,但是位置會根據(jù)軸心到錨點的距離一致的原則發(fā)生對應(yīng)的變化。

錨框形態(tài)下界面里數(shù)值的意義:下圖中,在黑框大小和位置變化的時候,會保證紅框的左下角到錨框的左下角距離不變,同時紅框的右上角到錨框的右上角距離不變。

錨點界面里數(shù)值的意義:Anchors的Min和Max分別是正規(guī)化的值(從0到1),表示占父矩形框的百分比。

RectTransform組件重要屬性 :?

軸心點就是UI元素旋轉(zhuǎn)和縮放的基準(zhǔn)點。

錨點在代碼里是由2個位置信息組成(對應(yīng)界面里的Anchors Min 和 Anchors Max),這倆個位置決定里錨框的范圍。

計算出來的UI元素的最終矩形框,該矩形框也是圖片填充的范圍。(只讀屬性)

錨點形態(tài)下表示的是UI元素的尺寸( size )

錨框形態(tài)下表示的是UI元素和錨框的尺寸差( delta )

所以這個變量被起名為sizeDelta

Question:在錨框形態(tài)下要怎么樣才能獲得UI元素的尺寸?

Recttransform.rect.width

Recttransform.rect.height

Question:在錨框形態(tài)下又怎么樣去設(shè)置UI元素的尺寸?

Recttransform.SetSizeWithCurrentAnchors(Animations.Axis axis,float size)

通俗講,在錨點形態(tài)下,該值就是表示錨點到UI軸心的矢量值。

通俗講,在錨框形態(tài)下,該值就是表示錨框里某一個點到UI軸心的矢量值。

UGUI原理的重要概念:

Canvas Batch:Canvas下的UI元素最終都會被Batch到同一個Mesh中,而在Batch前,會根據(jù)這些UI元素的材質(zhì)(通常就是Atlas)以及渲染順序進行重排,在不改變渲染結(jié)果的前提下,盡可能將相同材質(zhì)的UI元素合并在同一個SubMesh中,從而把DrawCall降到最低。Batch的結(jié)果會被緩存復(fù)用,直到這個Canvas被標(biāo)記為dirty。

Unity官方的重要提示:當(dāng)給定Canvas上的任何可繪制UI元素發(fā)生更改時,Canvas必須重新執(zhí)行合批過程。此過程重新分析Canvas上的每個可繪制UI元素,不管它是否被修改。注意,“更改”是指影響UI元素外觀的任何變動,包括修改sprite renderer的sprite、transform的position和scale、文本網(wǎng)格的text等。

?Canvas嵌套:Canvas可以嵌套使用,一個子Canvas下dirty的子物體不會觸發(fā)父Canvas的rebuild。

網(wǎng)格重建因素 :?

UI頂點屬性變化會引發(fā)網(wǎng)格更新

修改Image、Text的color屬性,會改變UIVertex.color

修改RectTransform的Size、Anchors、Pivot等,會改變UIVertex.position

注意:在UGUI中顏色的變化是通過修改頂點色實現(xiàn)的,避免生成了新的DrawCall

注意:UIVertex.position記錄的是本地空間下的坐標(biāo)

Rebuild流程圖


流程圖說明:

該過程由CanvasUpdateRegistry監(jiān)聽Canvas的WillRenderCanvases(上圖中1)而執(zhí)行,主要是對當(dāng)前標(biāo)記為dirty的layout和graphic執(zhí)行rebuild。

在rebuild layout之前會對Layout rebuild queue中的元素依據(jù)它們在heiarchy中的層次進行排序(上圖中的2),排列的結(jié)果是越靠近根的節(jié)點越會被優(yōu)先處理。

rebuild layout(上圖中的3),主要是執(zhí)行ILayoutElement和ILayoutController接口中的方法來計算位置,Rect的大小等布局信息。

rebulid graphic(上圖中的4),主要是調(diào)用UpdateGeometry重建網(wǎng)格的頂點數(shù)據(jù)(上圖中5)以及調(diào)用UpdateMeterial更新CanvasRender的材質(zhì)信息(上圖中6)。

合批原理:

?UGUI的合批規(guī)則是進行重疊檢測,然后分層合并。

第一步計算每個UI元素的層級號:如果有一個UI元素,它所占的矩形范圍內(nèi),如果沒有任何UI在它的底下,那么它的層級號就是0(最底下);如果有一個UI在其底下且該UI可以和它Batch,那它的層級號與底下的UI層級一樣;如果有一個UI在其底下但是無法與它Batch,那它的層級號為底下的UI的層級+1;如果有多個UI都在其下面,那么按前兩種方式遍歷計算所有的層級號,其中最大的那個作為自己的層級號。

第二步合并相同層級中可以Batch的元素作為一個批次,并對批次進行排序?:有了層級號之后,Unity會將每一層的所有元素進行一個排序(按照材質(zhì)、紋理等信息),合并掉可以Batch的元素成為一個批次。經(jīng)過以上排序,就可以得到一個有序的批次序列了。這時Unity會再做一個優(yōu)化,即如果相鄰間的兩個批次正好可以Batch的話就會進行Batch。合批的Batch數(shù)據(jù),最后會分別放在CanvasMesh的SubMesh里。

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? UGUI優(yōu)化

優(yōu)化Unity UI系統(tǒng)的首要任務(wù)是找到性能問題的準(zhǔn)確原因。

開發(fā)過程中四個常見的問題

過多的GPU片段著色器使用率(如屏幕填充率過高)

過多的CPU時間開銷在重建一個畫布上

過多的CPU時間開銷在生成頂點上(通常是文本)

過多的畫布重建次數(shù)

針對這四個問題來分組介紹優(yōu)化策略

網(wǎng)格重建優(yōu)化策略

屏幕填充率優(yōu)化策略

合批優(yōu)化策略

字體優(yōu)化策略

滾動視圖優(yōu)化策劃

其它優(yōu)化策略

網(wǎng)格重建優(yōu)化策略(Mesh)

使用盡可能少的UI元素:在制作UI時,一定要仔細(xì)查檢UI層級,刪除不必要的UI元素,這樣可以減少深度排序的時間以及Rebuild的時間。

減少Rebuild的頻率:將動態(tài)UI元素(頻繁改變例如頂點、alpha、坐標(biāo)和大小等的元素)與靜態(tài)UI元素分離出來,放到特定的Canvas中。

謹(jǐn)慎使用UI元素的active操作:因為它們會觸發(fā)耗時較高的rebuild。

謹(jǐn)慎使用Canvas的Pixel Perfect選項:該選項的開啟會導(dǎo)致UI元素在發(fā)生位移時,其長寬會被進行微調(diào)(為了對齊像素),從而造成layout Rebuild。(比如ScrollRect滾動時,會使得Canvas.SendWillRenderCanvas消耗較高)

Animator最佳用法: Animator每幀都會改變元素,即使動畫中的數(shù)值沒有變化,因為Animator沒有空指令檢查。對于僅響應(yīng)事件時才變化的元素,可以自行編寫代碼或使用第三方補間插件。

謹(jǐn)慎用Tiled類型的Image

屏幕填充率優(yōu)化策略(OverDraw):

禁用不可見的面板:比如當(dāng)打開一個系統(tǒng)時如果完全擋住了另外一個系統(tǒng),則可以將被遮擋住的系統(tǒng)面板禁用。(龍與少女優(yōu)化方案:通過修改Canvas對象的Layer隱藏面板。)

不要使用空的Image做按鍵響應(yīng):在Unity中Raycast使用Graphic作為基本元素來檢測touch。如果使用空的image也會產(chǎn)生不必要的overdraw。可以實現(xiàn)一個只在邏輯上響應(yīng)Raycast但是不參與繪制的組件即可。

Polygon Mode Sprites:如果圖片邊緣有大片留白就會產(chǎn)生很多無用填充。Unity和Texture Packer目前都支持了Polygon Mode,也就是說將原來的矩形Sprite用更加緊致的Polygon來描述。

Image Fill Center:在Image Type選項為Sliced的情況下,不需要Fill Center的時候去掉勾選。

合批優(yōu)化策略(DrawCall):

相同層級原則:父節(jié)點下所有子節(jié)點,盡量保持相同的層次結(jié)構(gòu)。相同層級下的UI元素可以Batch。

Mask組件:Mask組件使用了模版緩存,Mask中的UI元素?zé)o法與外界UI元素合批,Mask組件還會額外增加2個DrawCall.

隱藏的Image:Image組件中sprite為空,都是占用drawcall渲染的,并且還會打斷前后元素的合批。

Screen Space-Camera模式:一個Canvas中的任何一個UI元素只要在屏幕中,則這個Canvas中的其他UI元素即使在屏幕外DrawCall仍不會減少。

Hierarchy穿插重疊問題:如下圖紅點和Icon在不同圖集中,如果紅點稍微大一點,遮擋了旁邊的Icon,就不能合批,須要調(diào)整Icon和紅點的節(jié)點關(guān)系,4個Icons放在一個節(jié)點下,4個紅點放在一個借點下。


字體優(yōu)化策略(Font):

字體圖集的重建機制:當(dāng)一個新文字出現(xiàn)的時候,會被添加到字體圖集,如果圖集已經(jīng)沒有空余的地方,那么圖集會被重建。圖集會以相同的尺寸重建,打包當(dāng)前激活的所有UI text組件中要顯示的文字,如果發(fā)現(xiàn)圖集尺寸不夠用的時候,圖集會重新擴充尺寸。

后備字體機制:對于字體庫里沒有的文字,會被放進后備字體圖集里,后背字體圖集會常駐內(nèi)存里,不會被銷毀。后備字體取自于系統(tǒng)自帶的系統(tǒng)字庫Arial.ttf,在發(fā)布的游戲安裝包里該字庫是不存在的。我們在一些Unity開發(fā)的游戲里,偶爾會發(fā)現(xiàn)一些生僻字的字形和其它常見文字的字形不統(tǒng)一。

Text的網(wǎng)格重建:Text組件被重新啟用的時候,會重建Text的網(wǎng)格。如果含有大量的文字,會造成嚴(yán)重的CPU開銷。

提前生成動態(tài)字體:準(zhǔn)備游戲非常常用的文字集合,通過Font.RequestCharactersInTexture接口提前放入字體圖集里。注意使用Font.textureRebuilt 委托,在字體圖集被重新重建的時候,把我們提前準(zhǔn)備的文字集合再次添加進去。

使用美術(shù)數(shù)字:游戲的分?jǐn)?shù),可以使用美術(shù)數(shù)字(精靈圖片)來代替Text組件。

謹(jǐn)慎使用Text的Best Fit選項:雖然這個選項可以動態(tài)的調(diào)整字體大小以適應(yīng)UI布局而不會超框,但其代價是很高的,Unity會為用到的該元素所用到的所有字號生成圖元保存在圖集里,不但增加額外的生成時間,還會使得字體對應(yīng)的圖集變大。

減少長文本Text的變動,慎用UI/Effect:描邊和陰影效果都會增大四倍的頂點數(shù)

滾動視圖優(yōu)化策略(ScrollView):

有兩種方法填充滾動視圖:

1.用所有需要出現(xiàn)在滾動視圖的元素填充滾動視圖

2.用池處理這些元素,根據(jù)需要重新放置它們的位置

RectMask2D組件:倆種方法可以通過給滾動視圖添加一個RectMask2D組件來提高性能。該組件確保在滾動視圖窗口外面的滾動視圖元素不會出現(xiàn)在可畫的元素列表中,省去了該元素的batch。

一種簡單的緩存池策略:在UI中布局中,使用帶有Layout Element組件的對象占位( Slot )。給可見UI元素實例一個池,來填充滾動視圖看可見區(qū)域,Slot作為父物體來定位。

基于位置的緩存池策略:通過移動布局里UI元素的RectTransforms坐標(biāo)值,來排序顯示位置。通常寫一個自定義的滾動視圖類或者寫一個自定義布局組的組件。

其它優(yōu)化策略:

禁用無用的Raycast:UGUI的touch處理消耗也可能會成為性能熱點。因為UGUI在默認(rèn)情況下會對所有可見的Graphic組件調(diào)用raycast。對于不需要接收touch事件的grahic,一定要禁用raycast。(龍與少女為策劃提供了檢視的輔助腳本)

OverrideSorting:子Canvas中的OverrideSorting屬性將會造成Graphic Raycast測試停止遍歷Transform層級。

UI對象的坐標(biāo)Z值:Z值不為零的時候會影響對象渲染順序并不能合批。(例如:龍與少女里的陣型界面都是修改Spine的SortingOrder來實現(xiàn)位置排序)

網(wǎng)格開銷巨大:如果出現(xiàn)了WaitingForJob或PutGeometryJobFence,則說明合并網(wǎng)格開銷巨大(子線程網(wǎng)格合并)

高級技巧:對于處于選中播放動畫的需求,并且所處canvas下內(nèi)容比較多的情況下,可以單獨把選中對象放到預(yù)先建好的動態(tài)canvas里,取消選中時再放回去。

CanvasGroup的使用:

在窗口的GameObject上添加一個CanvasGroup,通過控制它的Alpha值來淡入或淡出整個窗口。

在窗口的GameObject上添加一個CanvasGroup,通過設(shè)置它Interactable值來控制底層所有控件的交互開關(guān)。

????????????????????????????????????????????????優(yōu)化工具

Profiler ,?FrameDebug?

? ??????????????????????????????????????????美術(shù)相關(guān)的制作規(guī)范

規(guī)范化的重要性:有規(guī)范就會有約束有限制,在一個團隊的角度上來講,大家遵守同一套規(guī)范,可以避免多余的溝通,增加開發(fā)效率,是保證團隊協(xié)作、項目穩(wěn)定推進的利器。

設(shè)計模板:根據(jù)游戲風(fēng)格和類型設(shè)計幾套模板:尺寸(比如大中小三套)、布局(比如左右,左中右等)、樣式(一級底+二級底+三級底)等,根據(jù)游戲內(nèi)容選擇模板,既保持UI統(tǒng)一,又能方便拼UI,大概百分之九十的窗口都在這幾個模板中選擇。其他比如充值等需要有表現(xiàn)力的窗口再自由設(shè)計尺寸和布局。

路徑一致性:美術(shù)UI目錄和客戶端目錄保持一致,可以很方便替換新版UI,而不會出現(xiàn)名字不一致,目錄不一致,策劃找瞎眼的情況。

圖片命名:可以參考功能、顏色、尺寸等特點命名,命名盡量使用英文,可以添加前綴表示所屬功能,后綴也可以使用拼音。

公用圖集:多個面板都會用到的圖片放到公用圖集里面。為了減少合批的障礙,有必要的時候,需要復(fù)制公共圖片到單獨的面板圖集里。

合理的出圖尺寸:可以減小硬盤大小,減少第一次導(dǎo)入項目時的圖片序列化時間。

圖片分類:圖片可以根據(jù)用途分為UISprite、UIFrame 、 Icon、Photo、背景原畫。

UISprite:盡量九宮格或者平鋪,并且盡量復(fù)用。

UIFrame:是一些尺寸巨大的背景框。

Photo:英雄形象等大尺寸圖片合并圖集太大,因此不會打進圖集。

字體大?。?/b>研發(fā)過程中確立大中小幾號字體。每級再分三類,一共九種字體大小。

色值表:顏色可以由美術(shù)出一張色值表,包括一種顏色的RGBA值和16進制值,方便開發(fā)人員快速定位準(zhǔn)確顏色。顏色值可以存儲在unity的顏色模板里。


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容