转载自:http://blog.csdn.net/yxriyin/article/details/44037673#reply
NGUI相当不错,但是有一点比较纠结的就是面板上显示特效的时候,要么UI盖住特效,要么面板永远无法盖住特效,很多人说修改renderqueue,然后就能显示了,几乎网上找到的方法都是粘贴复制的,不知道有没有自己去修改,反正我修改完是不靠谱的。今天找到一篇文章,转载自:http://blog.csdn.net/yxriyin/article/details/44037673#reply。经过反复试验成功了,不过需要两个panel
先上图:
可以看到,粒子在两个UISprite的中间。注意,这是两个panel,每个panel下各有一个UISprite。
一、原理:
NGUI通过调整renderqueue来显示不同层,然后他的shader是不写入z值得,然后特效刚好也不写入z值,所以你只要控制特效和UI的关系,确实只能通过renderqueue,但是如果你只是单纯让renderqueue非常大,那么特效永远在UI面板之上。
而我们游戏中多数特效需要加在两个面板之间,那么如何解决这个问题,就只能看NGUI的源代码了。
二、修改方案
public void UpdateSortUI()
{
if (this.widgetInFrontOfMe != null && this.widgetInFrontOfMe.drawCall != null)
{
int rq = this.widgetInFrontOfMe.drawCall.renderQueue + 1;
if(!AddQueue)
{
rq -= 2;
}
foreach (Material material in m_renderer.materials)
{
if(material.renderQueue != rq)
{
material.renderQueue = rq;
}
}
}
}
这段代码的功能就是把粒子的renderQueue放在widgetInFrontOfMe的对象上面,而widgetInFrontOfMe这个对象是某个panel下的对象,如UISprite。
然后,你如果在Update()或者LateUpdate中执行这段代码,你会发现它工作的不错,就是偶尔会闪一下,这是因为这段代码先更新了,然后NGUI才更新,所以导致滞后一帧。通过修改UIPanel的源代码,然后里面全部更新完毕后,再去调用这个函数,一切完美解决。
完整代码:
using UnityEngine;
using System.Collections;
public class UISortBehavior : MonoBehaviour {
public UIPanel panel;
public UIWidget widgetInFrontOfMe;
public bool AddQueue=true;
[System.NonSerialized]
Renderer m_renderer;
void Awake() {
m_renderer = this.renderer;
}
public void initPanel(UIPanel p)
{
panel = p;
}
void Start()
{
panel.addUISort (this);
}
public void UpdateSortUI()
{
if (this.widgetInFrontOfMe != null && this.widgetInFrontOfMe.drawCall != null)
{
int rq = this.widgetInFrontOfMe.drawCall.renderQueue + 1;
if(!AddQueue)
{
rq -= 2;
}
foreach (Material material in m_renderer.materials)
{
if(material.renderQueue != rq)
{
material.renderQueue = rq;
}
}
}
}
void OnDestroy()
{
if (panel != null)
{
panel.removeUISort (this);
}
}
}
注意:假如你在Inspector上拖拽初始化了panel对象,那么就不用调用initPanel方法了。
void LateUpdate ()
{
#if UNITY_EDITOR
if (mUpdateFrame != Time.frameCount || !Application.isPlaying)
#else
if (mUpdateFrame != Time.frameCount)
#endif
{
mUpdateFrame = Time.frameCount;
// Update each panel in order
for (int i = 0, imax = list.Count; i < imax; ++i)
list[i].UpdateSelf();
int rq = 3000;
// Update all draw calls, making them draw in the right order
for (int i = 0, imax = list.Count; i < imax; ++i)
{
UIPanel p = list[i];
if (p.renderQueue == RenderQueue.Automatic)
{
p.startingRenderQueue = rq;
p.UpdateDrawCalls();
// rq += p.drawCalls.Count;
rq += p.drawCalls.Count*2;
}
else if (p.renderQueue == RenderQueue.StartAt)
{
p.UpdateDrawCalls();
if (p.drawCalls.Count != 0)
// rq = Mathf.Max(rq, p.startingRenderQueue + p.drawCalls.Count);
rq = Mathf.Max (rq,p.startingRenderQueue + p.drawCalls.Count*2);
}
else // Explicit
{
p.UpdateDrawCalls();
if (p.drawCalls.Count != 0)
// rq = Mathf.Max(rq, p.startingRenderQueue + 1);
rq = Mathf.Max(rq,p.startingRenderQueue + 2);
}
p.updateUISort();
}
}
}
List<UISortBehavior> container = new List<UISortBehavior>();
public void addUISort(UISortBehavior uiSort)
{
if(container.Contains(uiSort))
{
return;
}
container.Add (uiSort);
}
public void removeUISort(UISortBehavior uiSort)
{
container.Remove (uiSort);
}
public void updateUISort()
{
for(int i = 0; i < container.Count; i++)
{
container[i].UpdateSortUI();
}
}
void UpdateDrawCalls ()
{
Transform trans = cachedTransform;
bool isUI = usedForUI;
if (clipping != UIDrawCall.Clipping.None)
{
drawCallClipRange = finalClipRegion;
drawCallClipRange.z *= 0.5f;
drawCallClipRange.w *= 0.5f;
}
else drawCallClipRange = Vector4.zero;
// Legacy functionality
if (drawCallClipRange.z == 0f) drawCallClipRange.z = Screen.width * 0.5f;
if (drawCallClipRange.w == 0f) drawCallClipRange.w = Screen.height * 0.5f;
// DirectX 9 half-pixel offset
if (halfPixelOffset)
{
drawCallClipRange.x -= 0.5f;
drawCallClipRange.y += 0.5f;
}
Vector3 pos;
if (isUI)
{
Transform parent = cachedTransform.parent;
pos = cachedTransform.localPosition;
if (parent != null)
{
float x = Mathf.Round(pos.x);
float y = Mathf.Round(pos.y);
drawCallClipRange.x += pos.x - x;
drawCallClipRange.y += pos.y - y;
pos.x = x;
pos.y = y;
pos = parent.TransformPoint(pos);
}
pos += drawCallOffset;
}
else pos = trans.position;
Quaternion rot = trans.rotation;
Vector3 scale = trans.lossyScale;
for (int i = 0; i < drawCalls.Count; ++i)
{
UIDrawCall dc = drawCalls[i];
Transform t = dc.cachedTransform;
t.position = pos;
t.rotation = rot;
t.localScale = scale;
// dc.renderQueue = (renderQueue == RenderQueue.Explicit) ? startingRenderQueue : startingRenderQueue + i;
dc.renderQueue = (renderQueue == RenderQueue.Explicit) ? startingRenderQueue : startingRenderQueue + i*2;
dc.alwaysOnScreen = alwaysOnScreen &&
(mClipping == UIDrawCall.Clipping.None || mClipping == UIDrawCall.Clipping.ConstrainButDontClip);
dc.sortingOrder = mSortingOrder;
// dc.clipTexture = mClipTexture;
}
}
使用方法:
1、粒子对象挂载UISortBehavior脚本
2、WidgetInFrontOfMe对象为粒子效果需要覆盖的对象
3、Panel为WidgetInFrontOfMe对象的panel
注意,遮挡不正常时,试着调一下panel的depth试试。