UGUI及NGUI实现粒子夹层渲染
我们在开发中,经常会遇见粒子,Mesh,Spine等在渲染的时候会被UI层给挡住从而无法达到理想的体验效果。现在我们来解决这些问题并实现夹层效果:
UGUI:
效果图:
Paste_Image.png我们可以看见粒子渲染在Pink的Image之上而在Green的Image下。实现了夹层效果。
技术实现
核心:通过脚本修改Canvas中的Order in layer。
- 首先我们需要修改Canvas的渲染模式。
- 在Unity中通过渲染队列来进行渲染的先后排序,从小到大分别为:
- Background
- Geometry(Opaque)
- Alpha Test
- Transparent
- Overlay。
- 我们修改Canvas的渲染模式为:Screen Space - Camera,并将我们的主摄像机赋予它。
-
接着我们编写脚本来更改需要修改Order的Sprite(Image)UIDepth。
using UnityEngine; using System.Collections; using UnityEngine.UI; public class UIDepth : MonoBehaviour { public int order; public bool isUI = true; void Start () { if(isUI) { Canvas canvas = GetComponent<Canvas>(); if( canvas == null){ canvas = gameObject.AddComponent<Canvas>(); } canvas.overrideSorting = true; canvas.sortingOrder = order; } else { Renderer []renders = GetComponentsInChildren<Renderer> (); foreach(Renderer render in renders){ render.sortingOrder = order; } } } }
-
将这么脚本赋予需要修改Order的Image。并修改Order。
- 最后修改粒子的Renerer,Canvas中默认的Order为0,我们修改了一个Image的Order为2,此时我们将粒子的Order修改为1.实现夹层。
NGUI:
NGUI也是基于MVC架构开发的插件。
- Model:UIGeometry。
- View: UIWidget。
- Control: UICamera。
三种解决方案:
- 修改NGUI中的UIPanel脚本中的默认的RenderQueue, 调整到3000以下,这样就不会遮挡住粒子特效了。
- 使用另外的一个摄像机来渲染粒子特效,缺点是UI窗口切换时,不易控制。
- 更改粒子特效的Shader中的RendererQueue值。
NGUI在渲染时,UIWidget会在LateUpdate中调用NGUI的UIDrawCall来完成渲染,我们可以通过自写代码,将我们需要渲染的Mesh,粒子等加入NGUI的Renderer Queue就能完成最完善的夹层渲染解决方案。(最佳方案)
-
这里介绍更改Renderer Queue的方法。
-
我们通过一个RenderQueueModifier 类来进行UIDrawCall的Renderer Queue顺序进行更改,让添加这个物体的对象参与渲染(在两个UIDrawCall中插入自己的Renderer Queue来实现夹层的层级排序)。
Paste_Image.png -
Target参数为:在谁的上层进行渲染。
using UnityEngine;
using System.Collections;
public class RenderQueueModifier : MonoBehaviour {
public UIPanel m_panel;
public UIWidget m_target;
public bool isForSpine = true;
public Renderer renderer;
void Awake() {
renderer = GetComponent<Renderer>();
}
void OnEnable() {
AddToPanel();
}
public void Set(UIPanel m_panel, UIWidget m_target, bool isForSpine)
{
this.m_panel = m_panel;
this.m_target = m_target;
this.isForSpine = isForSpine;
AddToPanel();
}
void AddToPanel() {
if (m_panel != null) m_panel.renderQueueModifiers.Add(this);
}
void OnDisable() {
m_panel.renderQueueModifiers.Remove(this);
}
int lasetQueue = int.MinValue;
public void setQueue(int queue)
{
if (this.lasetQueue != queue) {
this.lasetQueue = queue;
renderer.material.renderQueue = this.lasetQueue;
}
}
}
-
接着进行UIPanel的代码更改。
-
自己插入的Renderer Queue,参与DrawCall的渲染。
Paste_Image.png -
通过查找之前引用的Target的UIDrawCall,为我们将要插入的DrawCall留出空当。(将Mesh和粒子的渲染层级跟NGUI统一起来)
Paste_Image.png -
通过查找之前引用的Target的UIDrawCall,我们将我们的DC插入在Target的层级之上。
Paste_Image.png -
我们程序有多少个UIDrawCall进行刷新我们就通过刷新的时候让我们的自写的UIDrawCall也参与刷新显示。
Paste_Image.png