解决NGUI与粒子系统的遮挡问题

转载自: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试试。



评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值