蛮牛教育

接触unity3D也有一段时间了,基本上每周都能看到相关技术群有同学提问类似的问题。

当初我也遇到过同样的问题,后来在网上查看相关资料,最终根据自己的理解整理总结:

1.实现粒子效果显示在NGUI界面层级之间,无非动态改变相应材质的renderQueue值
2.常见显示需求:A界面(UIPanel)->B粒子效果->C界面(UIPanel)->D粒子效果。

===========================================

想要达到B粒子效果显示在A界面(UIPanel)之上C界面(UIPanel)之下
只需修改B粒子效果的renderQueue>A界面(UIPanel)所有材质的renderQueue && B粒子效果的renderQueue < c界面(UIPanel)所有材质的renderQueue值即可。

先上代码:RenderQueueManage.cs 类。

[C#] 纯文本查看 复制代码
using UnityEngine;

using System.Collections;

using System.Collections.Generic;

/**

 * @des:根据panel动态改变对象的渲染队列

 * @author:龙少
 * @注:直接挂在粒子效果的根对象上即可

 * @注:主要根据当前panel下最大渲染队列,动态改变此对象

 * ①.由于粒子效果默认renderQueue值为3000

 * ②.NGUI UIPanel默认值也为3000开始

 * ③.由于底层最终渲染顺序 (值从小到大)绘制drawCall先后顺序为(值从小到大)

 * ④.综合上述几点,为实现粒子效果在NGUI界面之间任意层,所以多出此脚本动态修改粒子对象的渲染队列值

 */

public class RenderQueueManage : MonoBehaviour {

    //需要添加在panel显示之上的粒子效果

    public  UIPanel  panel;

    private List<Material> listMaterial;


 
   void Start () {

        listMaterial = new List<Material> ();

        if (panel != null) {

            panel.addRenderQueueManage(this);
       

        }

        init ();

    }

 
    private void init(){

        setCollectMaterials (gameObject);

        setSortMaterialRenderQueue (listMaterial);

//      Debug.LogError ("<"+gameObject.name+">材质数:"+listMaterial.Count+"_排序完毕...");

//      foreach (Material mat in listMaterial) {

//          Debug.LogError ("<"+mat.name+">_渲染队列:"+mat.renderQueue);

//      }

    }

 
    /**

     * @des:刷新内容

     * @注:动态添加内容时,可添加完毕后刷新跟root

* @des:此接口可忽略,一般情况下不需调用

     */
    public void refreshRenderQueue(){

        listMaterial.Clear ();

        init ();

    }

 
   /**

     * @des:收集材质列表

     * @param:goChilid 当前镀锡

     */

    private void setCollectMaterials(GameObject goChild){

        // --收集自己

        Renderer render = goChild.transform.renderer;

        if (render != null) {

            Material [] mat = render.materials;

            if(mat!=null){

                listMaterial.AddRange(mat);
 
            }

        }

        int childCount = goChild.transform.childCount;

        if (childCount <= 0) {

            return;
    
 
       }

        for (int i=0; i<childCount; i++) {

            GameObject _go = goChild.transform.GetChild(i).gameObject;

            setCollectMaterials(_go);

            _go = null;

        }

    }


 
   /**

     *@des:排序材质球队列

     */

    private void setSortMaterialRenderQueue(List<Material> listMaterial){

        if (listMaterial == null || listMaterial.Count <= 1) {

            return;
     
        }

        listMaterial.Sort(delegate(Material x, Material y) {

            if(x.renderQueue>y.renderQueue){

                return 1;

            }

            if(x.renderQueue<y.renderQueue){

                return -1;

            }

            if(x.renderQueue == y.renderQueue){

                return 0;

            }

            return (x.GetInstanceID() < y.GetInstanceID()) ? -1 : 1;

        });

    }

 
   /**

     * @des:设置渲染队列值

     * @param:renderQueueValue 需改变值

     * @return true=成功 |false = 失败

     */

    public bool setRenderQueueValue(int renderQueueValue){

        int count = 0;

        if (listMaterial!=null && (count = listMaterial.Count)>0) {

            for(int i=0;i<count;i++){

                Material mat = listMaterial[i];

                if(mat!=null){

                  mat.renderQueue = renderQueueValue+i;

                }

                mat = null;

            }

            return true;

        }

        return false;

    }

 
   /**

     * @des:获取最大增量

     * @return 10;

     */

    public int getAddMaxRenderQueueValue(){

        if (listMaterial == null) {

            return 0;
       
        }

        return listMaterial.Count;

    }

 
    void OnDestroy(){

        if (panel != null) {

            panel.removeRenderQueueManage(this);
        
        }

        panel = null;

        listMaterial.Clear ();

        listMaterial = null;

    }

}

注意:
1.RenderQueueManage .cs 需要绑定在当前的粒子上
2.RenderQueueManage .cs 内对应public UIPanel panel;的定义。 panel即为粒子效果所需显示在某曾UI之上


接下来如何去动态计算各个层级所用材质的renderQueue值,如果大家有深入研究过NGUI的UIPanel会发现LateUpdate()下的逻辑。
先上一段自己添加的相关逻辑代码在UIPanel.cs文件夹下
注:需把一下代码片段添加到UIPanel.cs文件下

[C#] 纯文本查看 复制代码
private List<RenderQueueManage> listRenderQueueManage;


 
   /**

     * @des:添加一个需管理的对象到管理列表中

     * @param:renderQueueManage 需管理对象

     * @author:龙少

     */

    public void addRenderQueueManage(RenderQueueManage renderQueueManage){

        if (listRenderQueueManage == null) {

            listRenderQueueManage = new List<RenderQueueManage>();
        
}

        if (!listRenderQueueManage.Contains (renderQueueManage)) {

            listRenderQueueManage.Add(renderQueueManage);

        }

    }

 
   /**

     * @des:从列表中移除此管理内容

     * @param:renderQueueManage 所管理对象

     * @author:龙少

     */

    public void removeRenderQueueManage(RenderQueueManage renderQueueManage){

        if (listRenderQueueManage == null) {

            return;
     
   }

        if (listRenderQueueManage.Contains (renderQueueManage)) {

            listRenderQueueManage.Remove(renderQueueManage);

        }

    }

 
   /**

     *@des:设置更新渲染管理列表值

     *@param:value 设置值

     *@return int 返回当前队列

     *@author:龙少

     */

    private int setUpdateRenderQueueManageValue(int value){

        if (listRenderQueueManage == null) {

            return value-1;
     
   }

        int newRenderQueue = value;

        if (listRenderQueueManage != null) {

            foreach (RenderQueueManage rqm in listRenderQueueManage) {

                if(rqm.setRenderQueueValue(newRenderQueue)){

                    newRenderQueue = value+rqm.getAddMaxRenderQueueValue();

                }

            }

        }

        return newRenderQueue;

    }
最后添加相应逻辑调用即可,如

[C#] 纯文本查看 复制代码
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;

                }

                else if (p.renderQueue == RenderQueue.StartAt)

                {

                    p.UpdateDrawCalls();

                    if (p.drawCalls.Count != 0)

                        rq = Mathf.Max(rq, p.startingRenderQueue + p.drawCalls.Count);

                }

                else // Explicit

                {

                    p.UpdateDrawCalls();

                    if (p.drawCalls.Count != 0)

                        rq = Mathf.Max(rq, p.startingRenderQueue + 1);

                }

                /**

                 * @des:动态改变当前panel下粒子效果的renderQueue值

                 * @author:龙少

                 */

                rq = p.setUpdateRenderQueueManageValue(rq+1);

            }

        }

    }

在方法体内添加
rq = p.setUpdateRenderQueueManageValue(rq+1);

 


ok..完毕..希望对大家有所帮助~~
如有更好的解决方法可以留言讨论··