Unity中的粒子特效的 RendererQ 排序

Posted luguoshuai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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方法。

 

以上是关于Unity中的粒子特效的 RendererQ 排序的主要内容,如果未能解决你的问题,请参考以下文章

unity3d 在代码中怎样控制粒子特效的重新播放与停止?答案最好详细点,可以加分

Unity特效基础——粒子系统

Unity5.6.6升级到2018 碰到的粒子特效播放不出问题

Unity 3D学习笔记四十二:粒子特效

Unity3D_(Shuriken粒子系统)制作简单的烟花爆炸效果

Unity之粒子特效参数详解——中