NGUI处理特效显示和面板显示夹层问题
Posted AlanE
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NGUI处理特效显示和面板显示夹层问题相关的知识,希望对你有一定的参考价值。
NGUI相当不错,但是有一点比较纠结的就是面板上显示特效的时候,你会发现要么盖住特效,要么面板永远无法盖住特效。很多人说改renderqueue,然后就能显示了,然后下面一堆楼主给力。。。。呵呵。
先从原理上解释吧,NGUI是通过调整renderqueue来显示不同层,然后它的shader是不写入z值的,然后特效刚好也是不写入z值的,所以你
要控制特效和UI的关系,确实只能通过renderqueue.但是如果你只是单纯让renderqueue非常大,那么特效就会永远在面板之上。
如果你想要两个面板夹住特效,那么就需要看NGUI源代码了。
这里希望大家自己去看一下,我直接贴上修改方案:
if (this.widgetInFrontOfMe != null && this.widgetInFrontOfMe.drawCall != null) {
int rq = this.widgetInFrontOfMe.drawCall.renderQueue + 1;
Debug.Log(rq);
foreach (Material material in m_renderer.materials) {
if(material.renderQueue != rq)
{
material.renderQueue = rq;
}
}
}
首先这段代码就是将特效的renderqueu调整成你想要放置的物体的前面。然后你如果在Update()或者LateUpdate()中执行这
段代码,你会发现它工作的不错,就是偶尔会闪一下,这是因为这段代码先更新了,然后NGUI才更新,所以导致滞后一帧。对于我这种完美主义者来说,这是不
能接受的。所以我修改了UIPanel的源代码,然里面全部更新完毕后,再去调用这个函数。哈哈,一切都非常完美。
完整代码如下:using UnityEngine;
using System.Collections.Generic;
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);
}
}
当然UIPanel中也要修改:
void LateUpdate ()
{
if (mUpdateFrame != Time.frameCount)
{
mUpdateFrame = Time.frameCount;
// Update each panel in order
for (int i = 0; i < list.size; ++i)
list.UpdateSelf();
int rq = 3000;
// Update all draw calls, making them draw in the right order
for (int i = 0; i < list.size; ++i)
{
UIPanel p = list.buffer;
if (p.renderQueue == RenderQueue.Automatic)
{
p.startingRenderQueue = rq;
p.UpdateDrawCalls();
//rq += p.drawCalls.size;
rq += p.drawCalls.size * 2;
}
else if (p.renderQueue == RenderQueue.StartAt)
{
p.UpdateDrawCalls();
if (p.drawCalls.size != 0)
rq = Mathf.Max(rq, p.startingRenderQueue + p.drawCalls.size * 2);
//rq = Mathf.Max(rq, p.startingRenderQueue + p.drawCalls.size);
}
else // Explicit
{
p.UpdateDrawCalls();
if (p.drawCalls.size != 0)
rq = Mathf.Max(rq, p.startingRenderQueue + 2);
//rq = Mathf.Max(rq, p.startingRenderQueue + 1);
}
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.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;
// We want the position to always be on even pixels so that the
// panel‘s contents always appear pixel-perfect.
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.size; ++i)
{
UIDrawCall dc = drawCalls.buffer;
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);
#if !UNITY_3_5 && !UNITY_4_0 && !UNITY_4_1 && !UNITY_4_2
dc.sortingOrder = mSortingOrder;
#endif
}
}
以上是关于NGUI处理特效显示和面板显示夹层问题的主要内容,如果未能解决你的问题,请参考以下文章
csharp ScreenBase是Unity UI面板的基类。它处理转换,在屏幕显示和延迟之前和之后添加任务。它德
NGUI里使用UIDragDropItem的OnDragDropRelease时,surface总是显示UI Root的问题解决