Unity UGUI NGUI 模型 粒子特效 三者之間 渲染層級設置

目錄

一、介紹兩大UI插件NGUI和UGUI 
二、unity渲染順序控制方式 
三、NGUI的控制 
四、UGUI的控制 
五、模型深度的控制 
六、粒子特效深度控制 
七、NGUI與模型和粒子特效穿插層級管理 
八、UGUI與模型和粒子特效穿插層級管理程序員

寫在前面

這篇筆記是整理了以前作的記錄,在作項目的過程當中,遇到了各類各樣的界面穿插問題,界面層級混亂,好比,手機卡了或點快了,就致使兩個界面相互交叉。對於界面,這應該算是一個很嚴重的bug,很大部分緣由是整個UI框架沒有從總體上考慮這個,後來決心弄清楚層級的控制,並把一些對於目前項目可行的方法應用,界面穿插的問題少了不少,注意我只是在現有的框架打的補丁。若是是一個從頭開始,在架構UI的時候,這篇筆記應該會頗有用。架構

之前項目使用的NGUI插件,UI是有一我的擺放的,咱們客戶端就拿到這些prefab,添加相應的邏輯腳本。但偏偏是這個擺界面的人也沒有注意界面的層級,各個panel、各個weight的depth沒有統一管理,致使開發中後期,界面一多起來,不少界面同時出現的時候,panel和weight的層級就亂了。框架

unity有哪些GUI框架

  1. unity自帶的GUI系統 
    通常都不用它來開發遊戲,做爲拓展unity編輯器開發比較多,unity自帶的GUI效率很是低,每次渲染都是一個DrawCall,很差用,不能作到所見即所得。編輯器

  2. unity4.6以後的UGUI 
    UGUI是NGUI做者參與開發的,unity官方的新UI系統,感受挺好用的,至於效率問題應該比NGUI好些。5.x之後ugui有很大的提高,之後ugui應該會逐步替代ngui。 
    很早以前就嘗試過這套ugui系統,正是我在研究界面層級的時候,用NGUI顯示模型粒子特效沒有找到好的方法時,因而探索了ugui,具體怎麼控制層級,後面會討論。函數

  3. NGUI 
    是一個老牌的unity UI插件了,在ugui沒有推出以前,大部分unity的遊戲都使用的NGUI插件開發UI,它的好處不少,提供了常見的UI控件,實現幾乎全部須要的功能,在效率上也是控制嚴謹,DrawCall合併極大提高了控件渲染效率,還支持3D GUI。可是也有不少不足,版本更新太頻繁,版本bug不少,對於瞭解NGUI的開發者能夠很好利用它,但對於初學者來講,NGUI當然容易上手好用,可是對DrawCall的重建規則不瞭解,仍然會效率低下(後面會整理一下分析NGUI的筆記)。佈局

  4. FairyGUI 
    最近發現的一款跨平臺UI編輯器,組合各類複雜UI組件,以及爲UI設計動畫效果,無需編寫代碼,能夠一鍵導出Unity,Starling,Egret, LayaAir,Flash等多個主流應用和遊戲平臺。性能

    特性: 
    所見即所得。操做簡易,使用習慣與Adobe系列軟件保持一致,美術設計師能夠輕鬆上手。 
    在編輯器便可組合各類複雜UI組件,無需編寫代碼。不須要程序員編碼擴展UI組件。 
    強大的文本控件。支持動態字體,位圖字體,以及BMFont製做的位圖字體,支持HTML語法和UBB語法,支持圖文混排。 
    強大的列表控件,支持多種佈局,支持虛擬列表和循環列表,即便列表項目數量巨大也拒絕卡頓。 
    支持圖片的九宮格和平鋪處理,支持圖片變色和灰度,支持序列幀動畫編輯和使用。 
    內置手勢支持。 
    提供時間軸設計UI動效,可實時看到每幀的位置或其餘效果。 
    編輯狀態下使用分散的素材,發佈時自動打包圖集。支持定義多個圖集,自動支持抽出A通道的壓縮方式。 
    多國語言支持。 
    各類分辨率自適應。 
    提供插件機制,能夠根據項目的須要爲編輯器加入個性功能。 
    爲各個遊戲平臺提供了一致的API,得益於編輯器強大的編輯功能,程序員只須要了解少許API就能完成UI展示,相比Feathers, NGUI, UGUI等UI框架,FairyGUI提升了UI製做效率,下降了成本。測試

固然不止這些,還有許多UI框架,好比:Daikon Forge GUI、EZ GUI、2dTookit等等,有時間能夠看看,但目前主要用到的仍是NGUI、UGUI啦。字體

爲何要關心渲染順序?

  1. 若是是2D遊戲,渲染順序關係着每一個層次的顯示前後,好比UI在遊戲內容前面,遊戲內容又有多層次。舉一個簡單的例子,在橫版2D遊戲中,常常會用到多層滾動的背景,把遊戲物體分層管理起來,能夠有效的減小出錯概率,很好的控制顯示效果。動畫

  2. 對於3D遊戲,遊戲內容是3D的,UI通常是2D,有不少時候須要把某個模型啊,粒子特效啊,放在界面上,這樣就有一個問題,3D物體和2D界面的前後關係,好比有些界面是在模型之上的,有些在下面,嘗試過不少種辦法,都能實現需求,但不是每種辦法都是那麼舒服的。

unity中控制渲染順序的方式

  1. Camera 
    Camera是unity中最優先的渲染順序控制。depth越大,渲染順序越靠後。 
    這裏寫圖片描述

  2. sortingLayer 和 sortingOrder 
    對於這個屬性,我也是雲裏霧裏的,不是太明白。按照字面意思是層的排序,Canvas和Renderer都有這個屬性,unity官方就一句話帶過。優先級僅次於Camera的depth。 
    這裏寫圖片描述

    看網上的博客,通常都寫着sorting layer是比Camera低一層級的控制渲染順序的屬性。而後我作了不少嘗試,發現並非全部Renderer組件這個屬性做用,根據嘗試的結果,作以下總結:

    Canvas中的sorting layer能夠控制Canvas的層級,這是ugui中的東西,下面會討論的;

    GameObject中的renderer屬性就是掛在該GameObject的Renderer組件,Renderer是渲染組件的基類,下面有多個派生類,通過測試,目前知道的只有SpriteRenderer的sorting layer和sorting order能控制渲染順序。因此我也以爲,sorting layer和 sorting order就是unity 對2D遊戲所支持的吧;

    renderer組件有以下幾類: 
    這裏寫圖片描述

  3. RenderQueue 
    這是unity中的一個概念,(至少以前在opengl中沒聽過),大體意思就是渲染順序,那無疑就是控制渲染順序的嘛。 
    這裏寫圖片描述

因此通常設置材質的renderQueue或直接在shader中設置。

在ShaderLab中,有4個提早定義好的render queue,你能夠設置更多的在他們之間的值:

Background :表示渲染在任何物體以前 
Geometry(default):渲染大多數幾何物體所用的render queue 
AlphaTest:用於alpha測試 
Transparent:用於渲染半透明物體 
Overlay:渲染全部物體之上

There are four pre-defined render queues, but there can be more queues in between the predefined ones. The predefined queues are: 
Background - this render queue is rendered before any others. You’d typically use this for things that really need to be in the background. 
Geometry (default) - this is used for most objects. Opaque geometry uses this queue. 
AlphaTest - alpha tested geometry uses this queue. It’s a separate queue from Geometry one since it’s more efficient to render alpha-tested objects after all solid ones are drawn. 
Transparent - this render queue is rendered after Geometry and AlphaTest, in back-to-front order. Anything alpha-blended (i.e. shaders that don’t write to depth buffer) should go here (glass, particle effects). 
Overlay - this render queue is meant for overlay effects. Anything rendered last should go here (e.g. lens flares).

  1. 空間深度 
    在攝像機座標系下的Z軸,控制着該相機下的物體的深度,在fragment shader中進行深度測試,這樣就控制了渲染到屏幕的順序。(能夠看看深度測試的具體原理,就明白怎麼控制顯示的前後順序了)

NGUI控制渲染順序的方式

好了,講完了unity中的控制渲染順序的方法後,接下來聊兩個個UI系統獨有的方法了。首先說明一下,NGUI中空間位置不會影響屏幕顯示關係,由於在它內部處理頂點的時候,捨棄了Z座標值。

  1. UIPanel 
    首先講到的就是UIPanel,用過NGUI插件的朋友應該很是熟悉這個組件,未來會整理一篇分析NGUI的筆記,裏面會重點聊到UIPanel,因此這篇筆記就一筆帶過了:UIPanel很是重要。哈哈。

    1. depth: 
      NGUI中最正統的控制panel之間層級關係的就是 它的 depth 屬性。depth越大,越靠後渲染。 
      這裏寫圖片描述

    2. sorting order: 
      panel的該屬性也能夠控制panel的順序。 
      這裏寫圖片描述

    拓展

    它的優先級在depth以前,內部仍是經過設置render的sorting order來控制的。來看看一些源碼:

    UIPanel.cs

public int sortingOrder { get { return mSortingOrder; } set { if (mSortingOrder != value) { mSortingOrder = value; #if UNITY_EDITOR NGUITools.SetDirty(this); #endif UpdateDrawCalls(); } } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

而後查找了mSortingOrder的索引,發如今函數UpdateDrawCalls中使用了mSortingOrder 
這裏寫圖片描述

繼續跟蹤dc.sortingOrder 
這裏寫圖片描述

而後發現mRenderer是個 MeshRenderer類型的,在以前還說過,對render的sorting order不太明白,並不能控制渲染順序。然而NGUI內部卻使用了而且可以控制渲染順序。我就納悶了,而後在網上查了好久的資料,終於在雨鬆博客的評論區看到:unity中3D物體的Z的渲染區域 和UI的區域不同,必須一樣都是一個片才行。NGUI中生成的UIDrawCall裏面的Mesh都是片,因此sorting order對它有用,而以前說的之間建立一個cube,它是一個3D物體,3D物體和UI沒辦法經過它來控制層級的。

爲何panel中的depth比sorting order優先級低呢?

是由於panel的depth控制着UIDrawCall的生成順序,影響了RenderQueue的順序,前面已經提到過了,sorting order和sorting layer比RenderQueue優先級更高。

  1. UIWeight的depth 
    在同一個panel下的各個weight,能夠用weight的depth屬性來控制它們的先後關係。depth控制着weight在panel頂點重建時傳入的頂點序列,這個跟蹤一下NGUI源碼就知道了。(後面我會整理幾篇分析NGUI的文章,裏面包含這個)

  2. RenderQueue 
    在NGUI中使用這個屬性,就得先看看UIPanel關於RenderQueue的三種方式: 
    這裏寫圖片描述

    Automatic:由NGUI自動生成 
    StartAt:手動設置一個值 
    Explicit:同一個panel下的RenderQueue的值相同

    看代碼能夠理解一下,UIPanel.cs 
    這裏寫圖片描述

UGUI控制渲染順序的方式

  1. Canvas 
    不一樣Canvas之間能夠用如下兩個屬性控制渲染層級 
    Sorting Layer 
    Order in Layer

    Canvas和NGUI的UIPanel同樣,這些計算都不會管兩個之間的父子關係,有一個算一個。

  2. Hierarchy中順序 
    在同一個Canvas中,Hierarchy的順序決定了控件的層級關係。

模型深度的控制

  1. 空間深度 
    對於3D物體的顯示前後就是徹底按空間的前後來的,固然能夠在fragment shader中關閉深度測試,或進行其餘影響幀緩衝區的操做。就跟opengl中同樣了。

  2. RenderQueue 
    RenderQueue是對unity中全部能夠渲染的物體都適用。

補充:用Sorting Order能夠控制片模型的層級關係,NGUI中sorting order就是就是靠這種特性實現的。

粒子特效渲染層級的控制

  1. 空間深度 
    和3D模型一致。

  2. RenderQueue 
    和3D模型一致。

  3. sorting order 
    粒子系統自己是一個Renderer組件,它渲染的是一個一個精靈,是一個一個片,該屬性有效。

NGUI中讓模型穿插在兩個界面之間

通過上面的整理,已經明白了各個地方是能夠怎麼控制渲染順序了,接下來就來解決一些項目中遇到的問題。

NGUI中放3D模型,實現方法: 
1. 多個相機 
這種方法確定能夠實現,並且簡單粗暴。但仔細想一想,要作的決不只僅加個相機這麼簡單,我以前作的項目就是這麼搞得。而後……而後……在開發的中後期,各類bug就出來了,因爲多相機沒有管理好,各類問題真的很難纏,呵呵底層不是我寫的哈,因此咱們上層開發人員就補丁啊,整個項目代碼有些地方面目全非。

多相機其實就是利用Camera的depth來控制渲染順序的,通常來說,模型一個相機,UI一個相機,等等……你覺得兩個相機就夠了嗎?有沒有想過模型上可能還有界面呢?你可能說再加一個相機,可是有些需求每一個界面的跳轉都是多個的,並不能直接在作界面的時候就肯定哪一個界面在上面哪一個界面在下面,因此這樣的加多個相機並不可行。

那應該怎麼作?

後來想到一種辦法,就是每一個界面對應一個相機,一個相機照一個模型,或是在一塊兒顯示的模型,利用相機的depth來控制它們的遮擋關係,可是須要在客戶端框架中管理好相機,作一個「池子」,讓相機能夠複用,而且。可能你會擔憂性能問題,但這不是問題,一個遊戲中可能有不少界面,可是須要同時顯示的最多不超過五、6個吧,加上模型須要的,每次同時工做的撐死了就10個了,並且只要讓相機只照射到相應的界面,這就不會形成性能的損失,不一樣的只是變換矩陣而已。

  1. 用RenderQueue控制 
    相比於相機的管理,我以爲用RenderQueue來控制會更簡單一些,畢竟NGUI中也大量使用了RenderQueue來控制先後關係,能夠看看它們源碼: 
    這裏寫圖片描述

    這是在UIPanel中的LateUpdate,能夠看到三種模式下,RenderQueue具體值加的方式,通常咱們都是用Automatic模式,這種模式下是根據每一個UIPanel中生成的DrawCall自動計算RenderQueue的值。

    無論3D模型、粒子特效、仍是NGUI,均可以用RenderQueue來控制渲染順序,因此我想到了一個辦法。

    修改NGUI的源碼,讓兩個UIPanel的RenderQueue值間隔一些,空出幾個值用來設置給模型或粒子特效,很簡單: 
    這裏寫圖片描述

    看吧,是否是很簡單。而後只須要設置顯示在界面上的模型或粒子特效的RenderQueue爲這些空出來的值就好了。 
    這裏寫圖片描述

    這個腳本掛在相應的模型上,target表示 該模型要顯示在哪一個panel下面。

    A、B兩個界面,我把渲染順序調整後:A — 模型 — B

    到這裏只作好了一部分,咱們只是利用RenderQueue控制了渲染順序,可是空間的深度關係仍是在影響着在屏幕上顯示的前後關係。在fragment shader中會進行深度測試,無論你誰先渲染誰後渲染,只要全部物體渲染時都寫入深度緩衝區,那麼渲染順序並不能真正影響最後屏幕顯示的前後關係。

    因此還須要一步,就是在渲染模型時關閉深度測試,例如A、B兩個界面,模型在AB之間,那麼渲染流程以下:

    A — 關閉深度測試 — 模型 — 開啓深度測試 — B

    在shader lab中關閉深度測試的方法是:

ZWrite Off
  • 1

這裏提供一個簡單的shader:

Shader "Custom/DepthTest" { Properties { _MainTex ("Base (RGB)", 2D) = "white" {} } SubShader { Tags { "Queue"="Transparent" } ZWrite Off LOD 200 CGPROGRAM #pragma surface surf Lambert sampler2D _MainTex; struct Input { float2 uv_MainTex; }; void surf (Input IN, inout SurfaceOutput o) { half4 c = tex2D (_MainTex, IN.uv_MainTex); o.Albedo = c.rgb; o.Alpha = c.a; } ENDCG } FallBack "Diffuse" }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

補充:模型與模型之間也能夠用上面的這種渲染流程控制屏幕顯示的前後關係。

  1. 每次只顯示一個界面 
    在同一時間,屏幕上只顯示一個界面,每次打開新界面就隱藏下面的界面,連模型和粒子都隱藏掉。這樣就不存在兩個界面同時顯示的狀況了。

  2. 空間深度 
    在其它控制條件都相同的狀況下,NGUI和模型在一個相機下,受正常的渲染管線控制,也就是空間位置關係能夠影響渲染到屏幕的層級關係。注意模型的「厚度」。

NGUI中讓粒子特效穿插在兩個界面之間

粒子特效也可使用Camera的depth來控制,可是粒子特效會存在不少,因此用Camera並不可行,因此這裏就直接排除掉了。

  1. Sorting Order 
    粒子特效自己是用「點精靈」渲染的,每一個粒子就是一個點精靈,能夠看作一個片模型,而片模型就能夠受該屬性影響。

    能夠作一個測試,把下面腳本掛在粒子特效上:

public class SortUtil : MonoBehaviour { void Awake() { renderer.sortingOrder = 1; } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

sorting Order默認值爲0,現有A、B兩個界面,把A的panel設置爲0, B的panel設置2:

A:0 
粒子特效:1 
B:2

粒子特效恰好插在A、B之間,顯示效果也是粒子特效穿插在A、B之間。

補充:unity5.3後粒子特效支持了直接設置sorting order 
這裏寫圖片描述

  1. RenderQueue 
    這裏就沒有模型和NGUI交叉麻煩了,只須要完成RenderQueue的設置就能夠了,不須要改shader。

    假設A、B兩個界面,RenderQueue的值的大小關係: 
    A < 粒子特效 < B

    參照上面模型的具體方法,讓粒子特效的RenderQueue插在A、B兩個界面之間就能夠了。

UGUI中讓模型穿插在兩個界面之間

  1. 多個相機 
    一樣的,能夠用多個相機來作,但這種方式總歸是不太好,不推薦。

  2. shader lab 
    在fragment shader中利用傳入的Mask數據,去模型片斷數據進行篩選,符合條件的留下,不符合的丟棄。這種辦法其實也適用於NGUI。

    具體怎麼作的能夠參考雨鬆momo的一篇博文:這裏

  3. RenderTexture 
    UGUI中Image能夠接受一個材質,能夠把RenderTexture放在一個材質上。這樣就能夠按照UGUI自己的那些排序方式來控制了。

UGUI中讓粒子特效穿插在兩個界面之間

  1. sorting order 
    和NGUI同樣,一樣能夠用sorting order來控制,Canvas組件支持這些屬性。 
    這裏寫圖片描述

    雨鬆momo也過一篇文章,我這裏就再也不說了,這裏

總結

寫了這麼多,大體總結了常見的方式,比較熟悉NGUI,因此對於NGUI中各類都比較清楚,寫得比較詳細。對UGUI可能總結的不是很完整,因此之後還會繼續總結。在文章中提到了幾處shader lab的地方,我在這裏說明一下,利用shader lab也能夠完成以上各類遮擋關係,層級關係,但這篇文章沒有詳細講清楚,主要考慮到篇幅,因此後來會專門寫shader lab的實現方法,其思想和雨鬆momo的差很少。

寫在最後

以上這些東西都是在項目中實際遇到的問題,以及思考並試着用過的,如今將筆記整理成這篇文章,有什麼錯誤直接留言一塊兒討論,一塊兒成長。

相關文章
相關標籤/搜索