目錄
1族淮、介紹兩大UI插件NGUI和UGUI
2彰阴、unity渲染順序控制方式
3、NGUI的控制
4田盈、UGUI的控制
5畜号、模型深度的控制
6、粒子特效深度控制
7允瞧、NGUI與模型和粒子特效穿插層級管理
8简软、UGUI與模型和粒子特效穿插層級管理
寫在前面
這篇筆記是整理了之前做的記錄,在做項目的過程中述暂,遇到了各種各樣的界面穿插問題痹升,界面層級混亂,比如畦韭,手機卡了或點快了疼蛾,就導致兩個界面相互交叉。對于界面艺配,這應該算是一個很嚴重的bug察郁,很大部分原因是整個UI框架沒有從整體上考慮這個,后來決心弄清楚層級的控制转唉,并把一些對于目前項目可行的方法應用皮钠,界面穿插的問題少了很多,注意我只是在現有的框架打的補丁赠法。如果是一個從頭開始麦轰,在架構UI的時候,這篇筆記應該會很有用砖织。
以前項目使用的NGUI插件款侵,UI是有一個人擺放的,我們客戶端就拿到這些prefab侧纯,添加相應的邏輯腳本新锈。但恰恰是這個擺界面的人也沒有注意界面的層級,各個panel茂蚓、各個weight的depth沒有統(tǒng)一管理,導致開發(fā)中后期剃幌,界面一多起來聋涨,很多界面同時出現的時候,panel和weight的層級就亂了负乡。
unity有哪些GUI框架
unity自帶的GUI系統(tǒng)
一般都不用它來開發(fā)游戲牍白,作為拓展unity編輯器開發(fā)比較多,unity自帶的GUI效率非常低抖棘,每次渲染都是一個DrawCall茂腥,不好用狸涌,不能做到所見即所得。unity4.6之后的UGUI
UGUI是NGUI作者參與開發(fā)的最岗,unity官方的新UI系統(tǒng)帕胆,感覺挺好用的,至于效率問題應該比NGUI好些般渡。5.x以后ugui有很大的提升懒豹,以后ugui應該會逐步替代ngui。
很早之前就嘗試過這套ugui系統(tǒng)驯用,正是我在研究界面層級的時候脸秽,用NGUI顯示模型粒子特效沒有找到好的方法時,于是探索了ugui蝴乔,具體怎么控制層級记餐,后面會討論。NGUI
是一個老牌的unity UI插件了薇正,在ugui沒有推出之前片酝,大部分unity的游戲都使用的NGUI插件開發(fā)UI,它的好處很多铝穷,提供了常見的UI控件钠怯,實現幾乎所有需要的功能,在效率上也是控制嚴謹曙聂,DrawCall合并極大提升了控件渲染效率晦炊,還支持3D GUI。但是也有很多不足宁脊,版本更新太頻繁断国,版本bug很多,對于了解NGUI的開發(fā)者可以很好利用它榆苞,但對于初學者來說稳衬,NGUI固然容易上手好用,但是對DrawCall的重建規(guī)則不了解坐漏,仍然會效率低下(后面會整理一下分析NGUI的筆記)薄疚。FairyGUI
最近發(fā)現的一款跨平臺UI編輯器,組合各種復雜UI組件赊琳,以及為UI設計動畫效果街夭,無需編寫代碼,可以一鍵導出Unity躏筏,Starling板丽,Egret, LayaAir趁尼,Flash等多個主流應用和游戲平臺埃碱。
特性:
所見即所得猖辫。操作簡易,使用習慣與Adobe系列軟件保持一致砚殿,美術設計師可以輕松上手啃憎。
在編輯器即可組合各種復雜UI組件,無需編寫代碼瓮具。不需要程序員編碼擴展UI組件荧飞。
強大的文本控件。支持動態(tài)字體名党,位圖字體叹阔,以及BMFont制作的位圖字體,支持HTML語法和UBB語法传睹,支持圖文混排耳幢。
強大的列表控件,支持多種布局欧啤,支持虛擬列表和循環(huán)列表睛藻,即使列表項目數量巨大也拒絕卡頓。
支持圖片的九宮格和平鋪處理邢隧,支持圖片變色和灰度店印,支持序列幀動畫編輯和使用。
內置手勢支持倒慧。
提供時間軸設計UI動效按摘,可實時看到每幀的位置或其他效果。
編輯狀態(tài)下使用分散的素材纫谅,發(fā)布時自動打包圖集炫贤。支持定義多個圖集,自動支持抽出A通道的壓縮方式付秕。
多國語言支持兰珍。
各種分辨率自適應。
提供插件機制询吴,可以根據項目的需要為編輯器加入個性功能掠河。
為各個游戲平臺提供了一致的API,得益于編輯器強大的編輯功能猛计,程序員只需要了解少量API就能完成UI展現唠摹,相比Feathers, NGUI, UGUI等UI框架,FairyGUI提高了UI制作效率有滑,降低了成本跃闹。
當然不止這些嵌削,還有許多UI框架毛好,比如:Daikon Forge GUI望艺、EZ GUI、2dTookit等等肌访,有時間可以看看找默,但目前主要用到的還是NGUI、UGUI啦吼驶。
為什么要關心渲染順序惩激?
如果是2D游戲,渲染順序關系著每個層次的顯示先后蟹演,比如UI在游戲內容前面风钻,游戲內容又有多層次。舉一個簡單的例子酒请,在橫版2D游戲中骡技,經常會用到多層滾動的背景,把游戲物體分層管理起來羞反,可以有效的減少出錯幾率布朦,很好的控制顯示效果。
對于3D游戲昼窗,游戲內容是3D的是趴,UI一般是2D,有很多時候需要把某個模型啊澄惊,粒子特效啊唆途,放在界面上,這樣就有一個問題缤削,3D物體和2D界面的先后關系窘哈,比如有些界面是在模型之上的,有些在下面亭敢,嘗試過很多種辦法滚婉,都能實現需求,但不是每種辦法都是那么舒服的帅刀。
unity中控制渲染順序的方式
-
Camera
Camera是unity中最優(yōu)先的渲染順序控制让腹。depth越大,渲染順序越靠后扣溺。
clipboard.png -
sortingLayer 和 sortingOrder
對于這個屬性骇窍,我也是云里霧里的,不是太明白锥余。按照字面意思是層的排序腹纳,Canvas和Renderer都有這個屬性,unity官方就一句話帶過。優(yōu)先級僅次于Camera的depth嘲恍。
clipboard.png
看網上的博客足画,一般都寫著sorting layer是比Camera低一層級的控制渲染順序的屬性。然后我做了很多嘗試佃牛,發(fā)現并不是所有Renderer組件這個屬性作用淹辞,根據嘗試的結果,做如下總結:
Canvas中的sorting layer可以控制Canvas的層級俘侠,這是ugui中的東西象缀,下面會討論的;
GameObject中的renderer屬性就是掛在該GameObject的Renderer組件爷速,Renderer是渲染組件的基類央星,下面有多個派生類,經過測試惫东,目前知道的只有SpriteRenderer的sorting layer和sorting order能控制渲染順序等曼。所以我也覺得,sorting layer和 sorting order就是unity 對2D游戲所支持的吧凿蒜;
renderer組件有如下幾類:
-
RenderQueue
這是unity中的一個概念禁谦,(至少之前在opengl中沒聽過),大致意思就是渲染順序废封,那無疑就是控制渲染順序的嘛州泊。
clipboard.png
所以一般設置材質的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).
- 空間深度
在攝像機坐標系下的Z軸,控制著該相機下的物體的深度刽漂,在fragment shader中進行深度測試演训,這樣就控制了渲染到屏幕的順序。(可以看看深度測試的具體原理贝咙,就明白怎么控制顯示的先后順序了)
NGUI控制渲染順序的方式
好了样悟,講完了unity中的控制渲染順序的方法后,接下來聊兩個個UI系統(tǒng)獨有的方法了庭猩。首先說明一下窟她,NGUI中空間位置不會影響屏幕顯示關系,因為在它內部處理頂點的時候蔼水,舍棄了Z坐標值震糖。
UIPanel
首先講到的就是UIPanel,用過NGUI插件的朋友應該非常熟悉這個組件趴腋,將來會整理一篇分析NGUI的筆記吊说,里面會重點聊到UIPanel论咏,所以這篇筆記就一筆帶過了:UIPanel非常重要。哈哈颁井。-
depth:
NGUI中最正統(tǒng)的控制panel之間層級關系的就是 它的 depth 屬性潘靖。depth越大,越靠后渲染蚤蔓。
clipboard.png -
sorting order:
panel的該屬性也可以控制panel的順序。
clipboard.png
拓展
它的優(yōu)先級在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();
}
}
}
然后查找了mSortingOrder的索引,發(fā)現在函數UpdateDrawCalls中使用了mSortingOrder
繼續(xù)跟蹤dc.sortingOrder
然后發(fā)現mRenderer是個 MeshRenderer類型的贬芥,在之前還說過吐辙,對render的sorting order不太明白,并不能控制渲染順序蘸劈。然而NGUI內部卻使用了并且能夠控制渲染順序昏苏。我就納悶了,然后在網上查了很久的資料威沫,終于在雨松博客的評論區(qū)看到:unity中3D物體的Z的渲染區(qū)域 和UI的區(qū)域不一樣贤惯,必須同樣都是一個片才行。NGUI中生成的UIDrawCall里面的Mesh都是片棒掠,所以sorting order對它有用孵构,而之前說的之間創(chuàng)建一個cube,它是一個3D物體烟很,3D物體和UI沒辦法通過它來控制層級的颈墅。
為什么panel中的depth比sorting order優(yōu)先級低呢?
是因為panel的depth控制著UIDrawCall的生成順序雾袱,影響了RenderQueue的順序恤筛,前面已經提到過了,sorting order和sorting layer比RenderQueue優(yōu)先級更高芹橡。
UIWeight的depth
在同一個panel下的各個weight毒坛,可以用weight的depth屬性來控制它們的前后關系。depth控制著weight在panel頂點重建時傳入的頂點序列林说,這個跟蹤一下NGUI源碼就知道了粘驰。(后面我會整理幾篇分析NGUI的文章,里面包含這個)-
RenderQueue
在NGUI中使用這個屬性述么,就得先看看UIPanel關于RenderQueue的三種方式:
clipboard.png
Automatic:由NGUI自動生成
StartAt:手動設置一個值
Explicit:同一個panel下的RenderQueue的值相同
看代碼可以理解一下蝌数,UIPanel.cs
UGUI控制渲染順序的方式
- Canvas
不同Canvas之間可以用以下兩個屬性控制渲染層級
Sorting Layer
Order in Layer
Canvas和NGUI的UIPanel一樣,這些計算都不會管兩個之間的父子關系度秘,有一個算一個顶伞。
- Hierarchy中順序
在同一個Canvas中饵撑,Hierarchy的順序決定了控件的層級關系。
模型深度的控制
空間深度
對于3D物體的顯示先后就是完全按空間的先后來的唆貌,當然可以在fragment shader中關閉深度測試滑潘,或進行其他影響幀緩沖區(qū)的操作。就跟opengl中一樣了锨咙。RenderQueue
RenderQueue是對unity中所有可以渲染的物體都適用语卤。
補充:用Sorting Order可以控制片模型的層級關系,NGUI中sorting order就是就是靠這種特性實現的酪刀。
粒子特效渲染層級的控制
空間深度
和3D模型一致粹舵。RenderQueue
和3D模型一致。sorting order
粒子系統(tǒng)本身是一個Renderer組件骂倘,它渲染的是一個一個精靈眼滤,是一個一個片,該屬性有效历涝。
NGUI中讓模型穿插在兩個界面之間
經過上面的整理诅需,已經明白了各個地方是可以怎么控制渲染順序了,接下來就來解決一些項目中遇到的問題荧库。
NGUI中放3D模型堰塌,實現方法:
- 多個相機
這種方法肯定可以實現,而且簡單粗暴分衫。但仔細想想蔫仙,要做的決不僅僅加個相機這么簡單,我之前做的項目就是這么搞得丐箩。然后……然后……在開發(fā)的中后期摇邦,各種bug就出來了,由于多相機沒有管理好屎勘,各種問題真的很難纏施籍,呵呵底層不是我寫的哈,所以我們上層開發(fā)人員就補丁啊概漱,整個項目代碼有些地方面目全非丑慎。
多相機其實就是利用Camera的depth來控制渲染順序的,一般來講瓤摧,模型一個相機竿裂,UI一個相機,等等……你以為兩個相機就夠了嗎照弥?有沒有想過模型上可能還有界面呢腻异?你可能說再加一個相機,但是有些需求每個界面的跳轉都是多個的这揣,并不能直接在做界面的時候就確定哪個界面在上面哪個界面在下面悔常,所以這樣的加多個相機并不可行影斑。
那應該怎么做?
后來想到一種辦法机打,就是每個界面對應一個相機矫户,一個相機照一個模型,或是在一起顯示的模型残邀,利用相機的depth來控制它們的遮擋關系皆辽,但是需要在客戶端框架中管理好相機,做一個“池子”芥挣,讓相機可以復用驱闷,并且【判悖可能你會擔心性能問題,但這不是問題粘我,一個游戲中可能有很多界面鼓蜒,但是需要同時顯示的最多不超過5、6個吧征字,加上模型需要的都弹,每次同時工作的撐死了就10個了,而且只要讓相機只照射到相應的界面匙姜,這就不會造成性能的損失畅厢,不同的只是變換矩陣而已。
-
用RenderQueue控制
相比于相機的管理氮昧,我覺得用RenderQueue來控制會更簡單一些框杜,畢竟NGUI中也大量使用了RenderQueue來控制前后關系,可以看看它們源碼:
截圖.png
這是在UIPanel中的LateUpdate袖肥,可以看到三種模式下咪辱,RenderQueue具體值加的方式,一般我們都是用Automatic模式椎组,這種模式下是根據每個UIPanel中生成的DrawCall自動計算RenderQueue的值油狂。
不管3D模型、粒子特效寸癌、還是NGUI专筷,都可以用RenderQueue來控制渲染順序,所以我想到了一個辦法蒸苇。
修改NGUI的源碼磷蛹,讓兩個UIPanel的RenderQueue值間隔一些,空出幾個值用來設置給模型或粒子特效溪烤,很簡單:
看吧弦聂,是不是很簡單鸟辅。然后只需要設置顯示在界面上的模型或粒子特效的RenderQueue為這些空出來的值就行了。
這個腳本掛在相應的模型上莺葫,target表示 該模型要顯示在哪個panel下面匪凉。
A、B兩個界面捺檬,我把渲染順序調整后:A --- 模型 --- B
到這里只做好了一部分再层,我們只是利用RenderQueue控制了渲染順序,但是空間的深度關系還是在影響著在屏幕上顯示的先后關系堡纬。在fragment shader中會進行深度測試聂受,不管你誰先渲染誰后渲染,只要所有物體渲染時都寫入深度緩沖區(qū)烤镐,那么渲染順序并不能真正影響最后屏幕顯示的先后關系蛋济。
所以還需要一步,就是在渲染模型時關閉深度測試炮叶,例如A碗旅、B兩個界面,模型在AB之間镜悉,那么渲染流程如下:
A --- 關閉深度測試 --- 模型 --- 開啟深度測試 --- B
在shader lab中關閉深度測試的方法是:
ZWrite Off
這里提供一個簡單的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"
}
補充:模型與模型之間也可以用上面的這種渲染流程控制屏幕顯示的先后關系祟辟。
每次只顯示一個界面
在同一時間,屏幕上只顯示一個界面侣肄,每次打開新界面就隱藏下面的界面旧困,連模型和粒子都隱藏掉。這樣就不存在兩個界面同時顯示的情況了稼锅。空間深度
在其它控制條件都相同的情況下吼具,NGUI和模型在一個相機下,受正常的渲染管線控制矩距,也就是空間位置關系可以影響渲染到屏幕的層級關系馍悟。注意模型的“厚度”。
NGUI中讓粒子特效穿插在兩個界面之間
粒子特效也可以使用Camera的depth來控制剩晴,但是粒子特效會存在很多锣咒,所以用Camera并不可行,所以這里就直接排除掉了赞弥。
- Sorting Order
粒子特效本身是用“點精靈”渲染的毅整,每個粒子就是一個點精靈,可以看做一個片模型绽左,而片模型就可以受該屬性影響悼嫉。
可以做一個測試,把下面腳本掛在粒子特效上:
public class SortUtil : MonoBehaviour {
void Awake()
{
renderer.sortingOrder = 1;
}
}
sorting Order默認值為0拼窥,現有A戏蔑、B兩個界面蹋凝,把A的panel設置為0, B的panel設置2:
A:0
粒子特效:1
B:2
粒子特效剛好插在A总棵、B之間鳍寂,顯示效果也是粒子特效穿插在A、B之間情龄。
補充:unity5.3后粒子特效支持了直接設置sorting order
- RenderQueue
這里就沒有模型和NGUI交叉麻煩了迄汛,只需要完成RenderQueue的設置就可以了,不需要改shader骤视。
假設A鞍爱、B兩個界面,RenderQueue的值的大小關系:
A < 粒子特效 < B
參照上面模型的具體方法专酗,讓粒子特效的RenderQueue插在A睹逃、B兩個界面之間就可以了。
UGUI中讓模型穿插在兩個界面之間
多個相機
同樣的祷肯,可以用多個相機來做沉填,但這種方式總歸是不太好,不推薦躬柬。shader lab
在fragment shader中利用傳入的Mask數據拜轨,去模型片段數據進行篩選抽减,符合條件的留下允青,不符合的丟棄。這種辦法其實也適用于NGUI卵沉。
具體怎么做的可以參考雨松momo的一篇博文:這里颠锉。
- RenderTexture
UGUI中Image可以接受一個材質,可以把RenderTexture放在一個材質上史汗。這樣就可以按照UGUI本身的那些排序方式來控制了琼掠。
UGUI中讓粒子特效穿插在兩個界面之間
-
sorting order
和NGUI一樣,同樣可以用sorting order來控制停撞,Canvas組件支持這些屬性瓷蛙。
截圖.png
雨松momo也過一篇文章,我這里就不再說了戈毒,這里
總結
寫了這么多艰猬,大致總結了常見的方式,比較熟悉NGUI埋市,所以對于NGUI中各種都比較清楚冠桃,寫得比較詳細。對UGUI可能總結的不是很完整道宅,所以以后還會繼續(xù)總結食听。在文章中提到了幾處shader lab的地方胸蛛,我在這里說明一下,利用shader lab也可以完成以上各種遮擋關系樱报,層級關系葬项,但這篇文章沒有詳細講清楚,主要考慮到篇幅肃弟,所以后來會專門寫shader lab的實現方法玷室,其思想和雨松momo的差不多。
寫在最后
以上這些東西都是在項目中實際遇到的問題笤受,以及思考并試著用過的穷缤,現在將筆記整理成這篇文章,有什么錯誤直接留言一起討論箩兽,一起成長津肛。