Unity中的粒子特效的 RendererQ 排序
这里接https://www.cnblogs.com/luguoshuai/p/10021660.html
这里介绍两套粒子排序的方法。
首先声明,这两套排序方法均不是本人所写,是在项目开发的过程当中,看到同事的设计,然后我就记录了下来了,作为后续的学习与使用。
方法一:
1 using System.Collections.Generic; 2 using UnityEngine; 3 4 public class UIRenderQueueSorter : MonoBehaviour 5 { 6 [SerializeField] 7 UIWidget m_source; //基础RendererQ,粒子的 RendererQ 均是在此基础上递增的 8 [SerializeField] 9 int m_offset; //每次递增的幅度 10 [SerializeField] 11 List<Renderer> m_renderers = new List<Renderer>(); 12 13 public void Initialize() 14 { 15 Renderer[] renders = transform.GetComponentsInChildren<Renderer>(true); 16 m_renderers.AddRange(renders); 17 } 18 19 void Update() 20 { 21 if (m_source && m_renderers.Count > 0) 22 { 23 for (int i = 0; i < m_renderers.Count; i++) 24 { 25 Renderer r = m_renderers[i]; 26 if (r && r.sharedMaterial && m_source.drawCall != null) 27 r.sharedMaterial.renderQueue = m_source.drawCall.renderQueue + m_offset; 28 } 29 } 30 } 31 32 public void AddRenderer(Renderer r) 33 { 34 if (!m_renderers.Contains(r)) 35 { 36 m_renderers.Add(r); 37 } 38 } 39 40 public void ClearAllRenderers() 41 { 42 m_renderers.Clear(); 43 } 44 45 public UIWidget Source 46 { 47 set { m_source = value; } 48 } 49 50 public int Offset 51 { 52 set { m_offset = value; } 53 } 54 }
用法介绍,将该脚本挂载到粒子特效的父级对象上,使用的时候,只需要调用一下Initialize()方法即可。
方法二:
这个其实是对NGUI的一个简答扩展,粒子的 RendererQ 是以Panel为单位来计算的
对NGUI的修改,添加如下变量:
1 public List<UIParticlesEffectAutoSort> uiEffectList = new List<UIParticlesEffectAutoSort>();
修改NGUI的 LateUpdate 方法为如下:
1 void LateUpdate () 2 { 3 #if UNITY_EDITOR 4 if (mUpdateFrame != Time.frameCount || !Application.isPlaying) 5 #else 6 if (mUpdateFrame != Time.frameCount) 7 #endif 8 { 9 mUpdateFrame = Time.frameCount; 10 11 // Update each panel in order 12 for (int i = 0, imax = list.Count; i < imax; ++i) 13 list[i].UpdateSelf(); 14 15 int rq = 3000; 16 int addRq = 0; 17 18 // Update all draw calls, making them draw in the right order 19 for (int i = 0, imax = list.Count; i < imax; ++i) 20 { 21 UIPanel p = list[i]; 22 23 if (p.renderQueue == RenderQueue.Automatic) 24 { 25 p.startingRenderQueue = rq; 26 p.UpdateDrawCalls(); 27 rq += p.drawCalls.Count; 28 addRq = 0; 29 for(int j = 0; j < p.uiEffectList.Count; ++j) 30 { 31 addRq = Mathf.Max(addRq, p.uiEffectList[j].UpdateRendererQueue(rq)); 32 } 33 rq += addRq; 34 } 35 else if (p.renderQueue == RenderQueue.StartAt) 36 { 37 p.UpdateDrawCalls(); 38 if (p.drawCalls.Count != 0) 39 rq = Mathf.Max(rq, p.startingRenderQueue + p.drawCalls.Count); 40 } 41 else // Explicit 42 { 43 p.UpdateDrawCalls(); 44 if (p.drawCalls.Count != 0) 45 rq = Mathf.Max(rq, p.startingRenderQueue + 1); 46 } 47 } 48 } 49 }
UIParticlesEffectAutoSort:
1 using UnityEngine; 2 using System.Collections.Generic; 3 4 public class UIParticlesEffectAutoSort : MonoBehaviour 5 { 6 protected UIPanel panel; 7 protected List<Material> mats = new List<Material>(); 8 int beginRenderQ = -1, totalRenderQ = 0; 9 void Start() 10 { 11 panel = gameObject.GetComponentInParent<UIPanel>(); 12 if (panel == null) 13 { 14 enabled = false; 15 } 16 else 17 { 18 Renderer[] rds = gameObject.GetComponentsInChildren<Renderer>(true); 19 for (int i = 0; i < rds.Length; ++i) 20 { 21 for (int j = 0; j < rds[i].sharedMaterials.Length; ++j) 22 { 23 if (rds[i].sharedMaterials[j] != null) 24 mats.Add(rds[i].sharedMaterials[j]); 25 } 26 } 27 mats.Sort(delegate(Material a, Material b) 28 { 29 return a.renderQueue.CompareTo(b.renderQueue); 30 }); 31 panel.uiEffectList.Add(this); 32 } 33 } 34 void OnDestroy() 35 { 36 if (panel != null) 37 panel.uiEffectList.Remove(this); 38 } 39 public int UpdateRendererQueue(int rq) 40 { 41 if (panel == null) 42 return 0; 43 if (mats.Count > 0) 44 { 45 if (beginRenderQ != rq) 46 { 47 beginRenderQ = rq; 48 int tempRenderQ = -1, addRenderQ = 0; 49 for (int i = 0; i < mats.Count; ++i) 50 { 51 if (mats[i] == null) 52 continue; 53 if (tempRenderQ != mats[i].renderQueue) 54 { 55 tempRenderQ = mats[i].renderQueue; 56 ++addRenderQ; 57 } 58 mats[i].renderQueue = beginRenderQ + addRenderQ; 59 } 60 totalRenderQ = addRenderQ + 1; 61 } 62 return totalRenderQ; 63 } 64 return 0; 65 } 66 }
用法:将该脚本挂载到粒子特效的父级对象上即可。
需要注意的是,这两个方法都是调整的 sharedMaterials,如果在使用的过程中发现粒子的层级不正确,试着调整materials即可。
比如,方法二:
1 using System.Collections.Generic; 2 using UnityEngine; 3 4 public class UISelfParticalEffectAutoSort : UIParticlesEffectAutoSort 5 { 6 void Start() 7 { 8 panel = gameObject.GetComponentInParent<UIPanel>(); 9 if (panel == null) 10 { 11 enabled = false; 12 } 13 else 14 { 15 Renderer[] rds = gameObject.GetComponentsInChildren<Renderer>(true); 16 for (int i = 0; i < rds.Length; ++i) 17 { 18 for (int j = 0, jMax = rds[i].materials.Length; j < jMax; ++j) 19 { 20 if (rds[i].materials[j] != null) 21 mats.Add(rds[i].materials[j]); 22 } 23 } 24 mats.Sort(delegate(Material a, Material b) 25 { 26 return a.renderQueue.CompareTo(b.renderQueue); 27 }); 28 panel.uiEffectList.Add(this); 29 } 30 } 31 void OnDestroy() 32 { 33 if (panel != null) 34 panel.uiEffectList.Remove(this); 35 for (int i = mats.Count - 1; i >= 0; --i) 36 GameObject.Destroy(mats[i]); 37 mats.Clear(); 38 } 39 }
主要看Start方法。