【小松教你手遊開發】【unity實用技能】控制renderQueue解決NGUI與Unity3D物體渲染順序問題
http://gad.qq.com/college/articledetail/7082053
NGUI與Unity3D物體渲染順序問題,做UI的同學應該都遇到過。主要指的是UI與Unity製作的特效、3D人物等一同顯示時的層次問題。
之前鄧老師就這一問題,專門做了一次分享。鄧老師在分享時也指出了這類問題的根源:由於UI與特效等都是以transparent方式渲染,而Unity與NGUI在管理同是透明物體的render queue時實際上互相沒有感知,於是引出排序問題。鄧老師介紹了以Render To Texture方式解決這一問題的一種方法,文件見svn: /wlgame_proj/trunk/Client/Doc/規範文件/UI上的特效顯示.docx
然而使用rtt解決這類問題總感覺過重,且不夠靈活;而且rtt為了兼顧效率,紋理不可能設定太大,所以也導致了渲染精度降低、細節丟失的問題。
今天嘗試了另一種思路來解決這一問題:直接控制Unity中特效的render queue值,來達到使得UI、特效按照我們希望的順序進行渲染的目的。
先上效果圖,數字標註了不同的層次,按照0-7的順序疊加:
測試的工程地址:
\\......\......\03.客戶端\frank\UISandwichWithParticle.zip
測試場景為Assets\TestScene.unity。
另外這一工程中也包含了一個以鄧老師的方式解決這一問題的示例,場景為Assets\TestScene_orig.unity。
首先參考一下鄧老師方法中實現這類疊加後的Draw Call細節:
可以看到,因為所有元素最終都是以NGUI的元素進行管理的,draw call非常清晰,一層UI夾一層rtt紋理,render queue從3000開始依次排序下來,標準的多層三明治結構。
再來看另一種方式下UI的draw call細節:
這種方式下,UI和特效還是分開渲染的,所以NGUI的Draw Call統計裡只能看到UI的4個dc。注意,這裡手動設定了每個UI的render queue的值,分別是3000、3002、3004、3006,和上面的dc順序參照相對應的關係,可以發現是把用於特效渲染的render queue值(3001、3003、3005)給預留了出來。
這裡先插播一下關於設定UI的draw call的細節,也是這一方法中繁瑣的部分。我們知道NGUI會將採用同樣材質的widget合併到同一個draw call中進行渲染。然而在我們這個需求中,這一功能導致了無法在widget之間插入其它渲染佇列的問題,也就是原始的三明治問題。如果只是涉及到UI控制元件之間的穿插,NGUI可以通過depth設定來解決:
- 如果是使用同一材質的多個控制元件設定了不同的depth值,則NGUI還是將這些控制元件合併為同一個draw call,而在內部進行了排序;
- 如果設定了不同depth的多個控制元件,穿插使用了不同的材質,則NGUI會將其打散為不同的draw call,順序即按照depth指定。鄧老師的方式就用到的這一特性,其一共使用了2種材質而設定不同depth形成穿插關係,於是被打散成了7個dc。
我採用的方式,屬於上述第一種情況,無法簡單用depth設定來解決。為了將一個NGUI自動合併的dc打散,有多種hack的方式,這裡選擇的是手動給每個我們希望打散到不同dc的widget再新增一個panel的方式。增加panel原則上並不推薦,然而針對這一需求,實際上增加的空panel並不影響效能。其結果就是上圖中所示。
在為每個歸屬於不同層次的widget指定了所屬的render queue順序之後,剩下的就是為每個unity的特效指定應歸屬的render queue。
這裡引入了一個指令碼:RenderQueueModifier.cs(來源:http://www.tasharen.com/forum/index.php?topic=776.0)。使用時,需要將這一指令碼拖到對應的Unity的3D物體上
指定一個作為target的widget,以及排序方式即可。上圖的例子中,指定的target為card1,type為FRONT,含義是將這一特效指定為在Card1控制元件的前面。
其原理也較為簡單,直接貼原始碼:
using UnityEngine;
using System.Collections;
public class RenderQueueModifier : MonoBehaviour
{
public enum RenderType
{
FRONT,
BACK
}
public UIWidget m_target = null;
public RenderType m_type = RenderType.FRONT;
Renderer[] _renderers;
int _lastQueue = 0;
void Start ()
{
_renderers = GetComponentsInChildren<Renderer>();
}
void FixedUpdate() {
if( m_target == null || m_target.drawCall == null )
return;
int queue = m_target.drawCall.renderQueue;
queue += m_type == RenderType.FRONT ? 1 : -1;
if( _lastQueue != queue )
{
_lastQueue = queue;
foreach( Renderer r in _renderers )
{
r.material.renderQueue = _lastQueue;
}
}
}
}
可以看到,原理上就是直接修改這一特效下所有renderer組建中的material的renderQueue值,來按照需要指定。
還是以上面截圖的示例為例,Card1位於NGUI指定的render queue位置3000,則這個特效所在的render queue為3001,而在它之後render queue為3002的控制元件正好是控制元件Mask1。
所以和鄧老師方案最終的render queue效果相比較,其實算是殊途同歸,可以在不使用Render To Texture的情況下,達到更好的效果。
TODO:
- 偷懶所以手動新增的panel直接放在widget上,導致ngui會提示一條錯誤日誌。這個按照規範,將panel與widget設為父子結構即可
- RenderQueueModifier.cs指令碼還有優化的餘地,特別是可以增強編輯器支援,來達到不啟動遊戲即可實時檢視疊加效果的功能。
- 這個方案測試是在老版本的NGUI3.0.6中進行的。3.6版的新NGUI中,引入了手動修改render queue的功能,會更加方便為每個ui指定所屬的render queue。
最後,感謝在實驗過程中被我頻繁騷擾的鄧老師、ice、趙帆的耐心。:)
相關文章
- 【Unity3D開發小遊戲】《戰棋小遊戲》Unity開發教程Unity3D遊戲
- unity3D用滑鼠和射線控制物體移動Unity3D
- thymeleaf手動渲染@{}的問題與解決
- Unity3D 透明物體ShaderUnity3D
- unity3d縮放物體Unity3D
- unity3d Text莫名消失問題Unity3D
- Unity3D開發入門教程(四)——用Lua實現元件Unity3D元件
- unity3d開發的大型網路遊戲Unity3D遊戲
- Unity3D結合NGUI的螢幕自適應程式碼分享Unity3DNGUI
- THREE.js渲染順序JS
- 資料結構實驗一:順序表的建立與操作實現、順序表實現約瑟夫環問題資料結構
- Unity3D實時平面反射的擴充套件與應用Unity3D反射套件
- Unity3D引擎助力 《魔域手遊2》實機畫面效果展示Unity3D
- vue父子元件的渲染順序Vue元件
- MapStruct與lombok載入順序問題與annotationProcessorPaths的關係?StructLombok
- mysql order by 和 group by 順序問題MySql
- 移動端順序問題上
- Jetpack Compose的Modifier順序問題Jetpack
- Unity3D Demo專案開發記錄Unity3D
- Unity3d 切片不起作用的解決辦法!Unity3D
- 微信小程式wx.login先執行onLaunch與onLoad載入順序問題微信小程式
- 順序棧與鏈式棧的圖解與實現圖解
- 知物由學|遊戲開發者如何從容應對Unity手遊風險?遊戲開發Unity
- Unity3D 基礎自學學習筆記(二) Unity3D 基礎控制元件Unity3D筆記控制元件
- 《Unity 2D與3D手機遊戲開發實戰》簡介Unity3D遊戲開發
- 用 Nokitjs 解決前端開發中的跨域問題JS前端跨域
- 用 Unity 製作寫實渲染,畫面實現上需要注意的一些問題Unity
- GROUPBY 和開窗函式執行順序的問題函式
- Unity之掛載小問題Unity
- Unity3D相關面試題Unity3D面試題
- 區塊鏈遊戲的下一站:用小遊戲解決“大”問題區塊鏈遊戲
- Unity Webgl小遊戲存取資料的解決方案UnityWeb遊戲
- JavaScript萬物產生順序JavaScript
- 順序刷題
- Unity3d Android SDK接入解析(一)Unity3d 與 Android之間的互相呼叫Unity3DAndroid
- Unity3D如何開發最簡單的VR遊戲 vrPlus(神之眼)Unity3DVR遊戲
- 用分散式鎖解決併發問題分散式
- 簡單的演算法-解決頁面指令碼非同步載入順序問題演算法指令碼非同步
- 解碼智慧治理 用大資料解決民生小問題大資料