Unity NGUI 粒子的排序
Unity NGUI系统中是没有对粒子进行排序的,如:
怎么解决这个问题呢?
思路是把粒子的渲染层级,相对于UI组件的层级进行一个偏移。
解决后的效果如下:
代码如下:
新增脚本 UIRenderQueueSorter.cs:
1 using System.Collections.Generic; 2 using UnityEngine; 3 4 public class UIRenderQueueSorter : MonoBehaviour 5 { 6 [SerializeField] 7 UIWidget m_source; 8 [SerializeField] 9 int m_offset; 10 [SerializeField] 11 bool m_setToSameRQ = true; 12 13 List<Material> m_mats; 14 UIPanel m_panel; 15 int m_beginRQ, m_maxRQ; 16 17 18 public UIWidget Source 19 { 20 get => m_source; 21 set => m_source = value; 22 } 23 24 public int Offset 25 { 26 get => m_offset; 27 set => m_offset = value; 28 } 29 30 31 void OnEnable() 32 { 33 Initialize(); 34 } 35 36 public void Initialize() 37 { 38 m_beginRQ = -1; 39 m_maxRQ = 0; 40 41 m_panel = gameObject.GetComponentInParent<UIPanel>(); 42 if (!m_panel) 43 { 44 enabled = false; 45 return; 46 } 47 48 if (!m_panel.m_rqSorter.Contains(this)) 49 m_panel.m_rqSorter.Add(this); 50 51 if (m_mats == null) 52 m_mats = new List<Material>(); 53 else 54 m_mats.Clear(); 55 Renderer[] renders = transform.GetComponentsInChildren<Renderer>(true); 56 for (int i = 0; i < renders.Length; i++) 57 { 58 var r = renders[i]; 59 if (!r) 60 continue; 61 if (r is ParticleSystemRenderer psr) 62 { 63 psr.sortingOrder = 0; 64 if (psr.trailMaterial) 65 m_mats.Add(psr.trailMaterial); 66 } 67 if (r.sharedMaterial) 68 m_mats.Add(r.sharedMaterial); 69 } 70 71 m_mats.Sort((a, b) => a.renderQueue.CompareTo(b.renderQueue)); 72 } 73 74 public int UpdateRendererQueue(int panelRQ) 75 { 76 if (m_mats.Count < 1) 77 return 0; 78 79 int rq = Source && Source.drawCall ? Source.drawCall.renderQueue : panelRQ; 80 rq += Offset; 81 if (m_beginRQ == rq) 82 return m_maxRQ; 83 84 m_beginRQ = rq; 85 if (m_setToSameRQ) 86 { 87 for (int i = 0; i < m_mats.Count; ++i) 88 { 89 var mat = m_mats[i]; 90 if (mat) 91 mat.renderQueue = m_beginRQ; 92 } 93 m_maxRQ = m_beginRQ; 94 } 95 else 96 { 97 int tempRQ = -1, addRQ = 0; 98 for (int i = 0; i < m_mats.Count; ++i) 99 { 100 var mat = m_mats[i]; 101 if (mat == null) 102 continue; 103 if (tempRQ != mat.renderQueue) 104 { 105 tempRQ = mat.renderQueue; 106 ++addRQ; 107 } 108 m_maxRQ = m_beginRQ + addRQ; 109 mat.renderQueue = m_maxRQ; 110 } 111 } 112 return m_maxRQ; 113 } 114 115 void OnDestroy() 116 { 117 if (m_panel && m_panel.m_rqSorter != null) 118 m_panel.m_rqSorter.Remove(this); 119 } 120 121 }
同时修改NGUI 的 UIPanel.cs
1 public List<UIRenderQueueSorter> m_rqSorter = new List<UIRenderQueueSorter>(); 2 3 void LateUpdate () 4 { 5 #if UNITY_EDITOR && !UNITY_5_5_OR_NEWER 6 if (mUpdateFrame != Time.frameCount || !Application.isPlaying) 7 #else 8 if (mUpdateFrame != Time.frameCount) 9 #endif 10 { 11 mUpdateFrame = Time.frameCount; 12 13 // Update each panel in order 14 for (int i = 0, imax = list.Count; i < imax; ++i) 15 list[i].UpdateSelf(); 16 17 int rq = 3000; 18 19 // Update all draw calls, making them draw in the right order 20 for (int i = 0, imax = list.Count; i < imax; ++i) 21 { 22 UIPanel p = list[i]; 23 24 if (p.renderQueue == RenderQueue.Automatic) 25 { 26 p.startingRenderQueue = rq; 27 p.UpdateDrawCalls(i); 28 rq += p.drawCalls.Count; 29 30 // [dev] uipanel 的 render queue向后偏移 31 int maxRq = 0; 32 for (int k = 0; k < p.m_rqSorter.Count; k++) 33 maxRq = Mathf.Max(maxRq, p.m_rqSorter[k].UpdateRendererQueue(rq)); 34 rq = Mathf.Max(rq, maxRq + 1); 35 } 36 else if (p.renderQueue == RenderQueue.StartAt) 37 { 38 p.UpdateDrawCalls(i); 39 if (p.drawCalls.Count != 0) 40 rq = Mathf.Max(rq, p.startingRenderQueue + p.drawCalls.Count); 41 } 42 else // Explicit 43 { 44 p.UpdateDrawCalls(i); 45 if (p.drawCalls.Count != 0) 46 rq = Mathf.Max(rq, p.startingRenderQueue + 1); 47 } 48 } 49 } 50 }
用法:
1 // 特效排序 2 var sorter = m_effect.AddComponent<UIRenderQueueSorter>(); 3 sorter.Source = m_itemTexture; 4 sorter.Offset = 1; 5 sorter.Initialize();
此脚本将挂在需要排序的粒子的父节点上: