Unity4.6新UI系統初探(uGUI)


1、引言

Unity終於在即將到來的4.6版本內集成了所見即所得的UI解決方案(視頻)。事實上從近幾個版本開始,Unity就在爲這套系統作技術擴展,以保證最終能實現較理想的UI系統。本文試圖經過初步的介紹和試用,讓讀者對這套系統有大致的瞭解,以便更進一步評估這套UI系統好很差用,適合用在什麼項目。爲了不坑挖太深,更進一步的試用和評估我將在《用uGUI開發自定義Toggle Slider控件》中進行論述。爲論述方便,下文將這套New UI System簡稱爲uGUI,而且以X-UI指代現有第三方UI插件。 html

(測試只針對Unity 4.6.0 beta 10,正式版可能會有所出入。目前Unity沒提供文檔,本人半桶水,歡迎羣衆在微博或Issues裏吐槽!) git

2、Rect Transform

Rect Transform

Rect Transform繼承自Transform,是uGUI相比X-UI最顯著的區別[注1]。當你爲Empty GameObject加入一個UI Component時,Transform會自動轉換爲Rect Transform。Rect Transform儘可能整合了X-UI常見的anchor(相對父物體的錨點), pivot(中點), stretch(拉伸)等屬性。值得一提的是,這裏的anchor是Rect而非Vector2,由於它不只用於偏移,並且用於縮放。點擊Rect Transform上的準心圖標,還能在彈出的Anchor Presets面板中對其進行快速設置。 github

Anchor Presets

這個面板仍是不夠直觀,咱們能夠把它當作一張表,上面四個圖標用於設置列,左邊四個圖標用於設置行,也能夠直接點擊裏面的16個圖標同時設置行和列。強大的地方是,按住shift時能同時設置pivot,這時能發現控件雖然不動但position已經在改變。若是按住alt,則設置anchor的同時設置position。若是shift和alt同時按住,那麼你就能同時設置anchor, pivot和position。這個操做方式比起X-UI,真的高明不少,對多分辨率適配頗有幫助。 算法

除此以外,Rect Transform還提供了Blueprint和Lock Rect選項,前者用於對旋轉過的元素進行定位,後者聽說明是能在設置anchor時保持位置不變,暫時沒搞明白。 canvas

3、排序

SortHierarchy

uGUI能夠直接在Hierarchy面板中上下拖拽來對渲染進行排序(支持程序控制),越上面的UI會越先被渲染,相比X-UI的global depth排序,這樣的拖拽設計很討好用戶。同時在結構上則和ex2D採用的local depth相似,這樣GO只和同級其它GO進行排序,開發組件會很方便。須要注意的是,這裏排序只是相對UI而言,其它3D物體仍是按原先的次序渲染,而且UI老是渲染在3D物體上面。這就致使你不能像用ex2D那樣直接將粒子系統插入到兩個UI之間。 緩存

這種無需填寫depth值的排序方式,容易致使沒有手工作sprite packing的free版用戶遇到draw call增長。由於全部物體的depth都是自動設置的,Unity保證了每一個物體的depth都是惟一的。這時假設你有一個格子控件,每一個控件用到了兩個Sprite,但你並無把Sprite都拼到同一張貼圖上。因而你每複製一個新的格子出來,draw call就會增長2個,由於Unity會以格子爲單位依次繪製。pro用戶因爲有sprite packing機制,不用擔憂這個問題。(這種狀況在ex2D裏,是以默認提供"unordered"的渲染方式來解決的,這也是NGUI的默認作法。在這種狀況下ex2D會優先以相同depth的相同Sprite爲單位繪製,所以不論有多少個格子,draw call都是2個。除非你就是但願以格子爲單位進行渲染[注6],那麼你能夠在ex2D裏設置渲染方式爲"ordered",或者在NGUI裏給每一個格子設置不一樣的depth。 架構

4、控件

UI Component

uGUI自帶了以上控件,其中Image用於顯示Sprite,Raw Image用於顯示Texture,Image Mask和Rect Mask用於clipping。全部控件都是MonoBehaviour,能夠直接從Inspector裏拖到其它GameObject上。 框架

4.1 Image

Image

uGUI用Image控件顯示圖片,圖片就是一個Sprite,這意味着Pro用戶不用再製做atlas了,相比X-UI是個大進步,Free用戶同樣能夠手動作Packing。Image提供了SimpleSlicedTiledFilled四種效果,和X-UI保持一致。 ide

4.2 Button

Button

uGUI裏,Button控件由兩個GameObject組成,一個包含Image, Button等Component,一個包含Text等Component。這樣設計很組件化,惟一的問題是當用戶想修改Button時,容易不當心選中Label或其它實體。 工具

Button Component主要執行Transition和事件兩個操做。

  • Transition可選擇改變顏色、更換貼圖或自定義動畫,使用起來簡單方便,也能利用動畫定義更豐富的表現。我會再寫一篇文章演示Button的Transition。
  • 事件也是所見即所得的,在OnClick裏面能夠添加多個命令,命令能夠選擇對應的目標、操做和參數。用法簡單,有須要也能夠換程序控制。
    • 目標能夠是任意Object,例如其它GameObject或者Project裏的Asset
    • 操做能夠是須要設置的參數或調用的方法
    • 參數分紅Dynamic和Static,Dynamic能將控件的參數單向綁定到目標參數,Static則將目標參數設置成預設值。按鈕沒有Dynamic參數,Toggle, Slider等控件纔有。

5、事件

5.1 Event Trigger

Event Trigger

uGUI控件每每只提供一個自帶事件,要響應更多基本事件的話,須要添加Event Trigger組件。Event Trigger包含如下事件:

  • PointerEnter, PointerExit, PointerDown, PointerUp, PointerClick
  • Move, Drag, Drop, Scroll
  • KeyDown, KeyUp, Select, Deselect

能夠在Event Trigger中Add多個事件,每一個事件均可以添加多個命令,用法和控件自帶事件一致。

5.2 Graphic Raycaster

Graphic Raycaster

每一個Canvas都有一個Graphic Raycaster,用於獲取用戶選中的uGUI控件。多個Canvas之間經過設置Graphic Raycaster的priority來設置事件響應的前後次序。當Canvas採用World Space或Camera Space時,Graphic Raycaster的Block選項能夠用來設置遮擋目標。

5.3 Event System

Event System

建立uGUI控件後,Unity會同時建立一個[注4]叫EventSystem的GameObject,用於控制各種事件。能夠看到Unity自帶了兩個Input Module,一個用於響應標準輸入,一個用於響應觸摸操做。Input Module封裝了對Input模塊的調用,根據用戶操做觸發各Event Trigger。理論上咱們能夠編寫本身的Input Module,用來封裝各類外部設備的輸入,只要加入Event System所在的GameObject就行。

Event System組件則統一管理多個Input Module和各類Raycaster。它每一幀調用多個Input Module處理用戶操做,也負責調用多個Raycaster用於獲取用戶點擊的uGUI控件以及2D和3D物體。

6、性能

2D渲染分兩大類,一類是單純的Sprite繪製,用於渲染場景、角色、粒子等,另外一類是UI繪製。Unity將這兩類需求劃分紅了SpriteRendereruGUI兩部分,前者由Transform + SpriteRenderer實現,後者由Rect Transform + CanvasRenderer + UI控件 + Canvas[注2]實現,這樣的兩套相對獨立的機制比起X-UI的UI控件繼承自SpriteRenderer更爲合理。由於在2D遊戲裏SpriteRenderer只須要關心最基本的面片渲染,注重效率,而UI注重各種變換、對齊、操做、動畫,還經常須要Resize VBO。若是SpriteRenderer在設計上須要兼顧UI,就會像X-UI那樣設計得太過複雜,在用戶體驗和性能上都很很差。

這裏咱們探討一下uGUI的渲染機制,當咱們渲染多個使用相同Sprite的控件時,並沒發生dynamic batching,可是drawcall也沒有上升。這就說明Unity在內部使用了專門的一套batching機制,把多個控件的VBO事先合併成了一個。也就是說CanvasRenderer不負責實際渲染,而是由Canvas批量渲染多個CanvasRenderer,這和部分X-UI採用的作法一致。這樣單獨batch的設計有可能使得性能比SpriteRenderer好,也可能致使性能更差。性能會更好的狀況在ex2D裏已經證明了,主要緣由是這樣能更好的平衡CPU和GPU負載,而且能作到更優化的batching算法。性能更差的狀況,在去年舊版的NGUI測試時也遇到了,根本緣由仍是優化不到位致使的(不是貶低,不一樣工具的取捨和麪向市場都不一樣)。而Unity的 SpriteRenderer在手機上的渲染跑分是和ex2D持平的,CanvasRenderer又比SpriteRenderer快[注3],所以uGUI的性能不用擔憂。因爲目前沒有Mac版本,我會在正式版發佈後進行一次手機跑分測試。

7、小結

uGUI功能完善,操做簡潔,很接地氣。能夠說uGUI是相對X-UI的全面升級,總體架構更爲嚴謹,實現更爲清晰。依託4.5的Module Manager,uGUI以Package的形式提供,也能得到快速的升級[注5]。做爲ex2D v2.0開發者之一,我很看好它未來的發展,uGUI將在大多數場合取代X-UI。

初步感覺:

7.1 亮點

  • RectTransform
  • Event/單向數據綁定
  • 直接在Hierarchy中排序
  • Pro用戶可用Sprite的動態拼圖,無需手工拼圖

7.2 不足

7.3 小遺憾

  • Anchor Presets面板還不夠直觀。
  • 用戶想修改Button時,很容易修改到Label。
  • 當Hierarchy面板內的目標節點展開子節點後,沒法將其它節點直接拖動到目標的正下方。

7.4 小問題

  • Input組件對方向鍵的支持有問題。
  • Game View dock到主窗口後,top定位有誤,把toolbar的高度也算進去了。

8、附註

  1. 咱們在其它平臺上開發類 Entity-Component框架時,討論過Unity爲何不在底層對transform作特殊處理,以免插件做者手工緩存transform來優化query transform引發的開銷,甚至是將transform直接整合進GameObject。緣由是如今的transform是3D的,未來徹底可能推出 2D Transform。因此Unity在以前的版本里一直保留着transform的獨立性。
  2. 我不能徹底確定必定是Canvas,但經過Canvas和CanvasRenderer的接口來看,這個可能性很大。
  3. 基於更好的平衡CPU和GPU負載 + 更優化的batching算法,以Unity的實力CanvasRenderer超越SpriteRenderer問題不大。並且若是性能不會提高,uGUI只要像2D Toolkit那樣給每一個控件直接添加MeshRenderer,也就是說uGUI直接用已有的SpriteRenderer就好,不太可能加入新的CanvasRenderer性能反而更慢。
  4. Unity容許多個Event System同時存在,但同一時刻只有一個可以生效。
  5. uGUI的控件、Event等模塊以包的形式提供,位於程序目錄下的%UNITY%\Editor\Data\UnityExtensions\Unity\GUISystem\4.6.0,Unity 提供了兩個運行時版本的DLL,分別用於創做和發佈。區別主要是發佈版不含一些Editor中才用獲得的代碼。因爲DLL沒辦法經過預編譯符號來進行條件編譯,所以Unity使用這種方式進行權衡,用戶發佈時無需手工切換DLL版本,知足了閉源,又兼顧了執行效率。這樣就甩開了第三方插件幾條街,不少插件在這個問題上不是犧牲性能就是無奈開源。
  6. 有時仍是會須要以格子爲單位渲染,例如當格子之間須要重合,這種需求在UI裏不常見。
相關文章
相關標籤/搜索