NGUI中穿插粒子或者mesh渲染层级

NGUI中穿插粒子或者mesh渲染层级

大家好,又见面了,我是全栈君。

  在项目中由于特效的层级与NGUI UI的层级不太还规范,导致特效的渲染层级较为杂乱于是就想把特效层级与NGUI的层级管理混合在一起;

  在修改之前首先要了解NGUI的层级管理以及DC的合并:

   在NGUI中层级的管理以及Drawcall的合并都是由UIPanel这个组件来完成的;在NGUI中UIpanel就相当于UGUI中canvas和canvasrender,在UIpanel中会维护两个队列分别是UIWidget和UIDrawcall的队列并按照深度排序;

每当该UIPanel下有UIWidget的信息改变例如可见性或者是大小等改变的时候这个UIpanel就会刷新该panel的所有UIWidget并重新生成UIdrawcall进行合并;而说到合并Drawcall在NGUI中是按照就近合并的原则:当下一个Drawcall(即UIWidget组件的派生组件如UIsprite等的材质,贴图和shader)和上一个完全一样的时候则合并两个Drawcall;在生成并排序合并之后就开始按照既定的顺序开始指定每个Drawcall的渲染层级,而对于同一个Drawcall的不同元素则通过shader进行相对排序显示。基本流程讲完了上代码:

 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 // updateself开始刷新widget并排序
15             int rq = 3000;
16 
17             // Update all draw calls, making them draw in the right order
18             for (int i = 0, imax = list.Count; i < imax; ++i)
19             {
20                 UIPanel p = list[i];
21 
22                 if (p.renderQueue == RenderQueue.Automatic)
23                 {
24 // 循环分配渲染层级
25                     p.startingRenderQueue = rq;
26                     p.UpdateDrawCalls();
27                     rq += p.drawCalls.Count;
28                 }
29                 else if (p.renderQueue == RenderQueue.StartAt)
30                 {
31 // 循环分配渲染层级
32                     p.UpdateDrawCalls();
33                     if (p.drawCalls.Count != 0)
34                         rq = Mathf.Max(rq, p.startingRenderQueue + p.drawCalls.Count);
35                 }
36                 else // Explicit
37                 {
38 // 循环分配渲染层级
39                     p.UpdateDrawCalls();
40                     if (p.drawCalls.Count != 0)
41                         rq = Mathf.Max(rq, p.startingRenderQueue + 1);
42                 }
43             }
44         }
45     }
46 void UpdateSelf ()
47     {
48         mUpdateTime = RealTime.time;
49 
50         UpdateTransformMatrix();
51         UpdateLayers();
52 // 更新widget并排序
53         UpdateWidgets();
54 
55         if (mRebuild)
56         {
57             mRebuild = false;
58 // 重新绘制合并排序DC
59             FillAllDrawCalls();
60         }
61         else
62         {
63 // 移除不可用dc
64             for (int i = 0; i < drawCalls.Count; )
65             {
66                 UIDrawCall dc = drawCalls[i];
67 
68                 if (dc.isDirty && !FillDrawCall(dc))
69                 {
70                     UIDrawCall.Destroy(dc);
71                     drawCalls.RemoveAt(i);
72                     continue;
73                 }
74                 ++i;
75             }
76         }
77 
78         if (mUpdateScroll)
79         {
80             mUpdateScroll = false;
81             UIScrollView sv = GetComponent<UIScrollView>();
82             if (sv != null) sv.UpdateScrollbars();
83         }
84     }

 

 1     void FillAllDrawCalls ()
 2     {
 3         for (int i = 0; i < drawCalls.Count; ++i)
 4             UIDrawCall.Destroy(drawCalls[i]);
 5         drawCalls.Clear();
 6     
 7         Material mat = null;
 8         Texture tex = null;
 9         Shader sdr = null;
10         UIDrawCall dc = null;
11      // widget排序
12         if (mSortWidgets) SortWidgets();
13      // 根据既定顺序开始生成Drawcall并合并
14         for (int i = 0; i < widgets.Count; ++i)
15         {
16             UIWidget w = widgets[i];
17 
18             if (w.isVisible && w.hasVertices)
19             {
20                 Material mt = w.material;
21                 Texture tx = w.mainTexture;
22                 Shader sd = w.shader;
23           
24                 if (mat != mt || tex != tx || sdr != sd)
25                 {
    
    
             // 跟上一个不同重新生成DC
26 if (dc != null && dc.verts.size != 0) 27 { 28 drawCalls.Add(dc); 29 dc.UpdateGeometry(); 30 dc = null; 31 } 32 33 mat = mt; 34 tex = tx; 35 sdr = sd; 36 } 37 38 if (mat != null || sdr != null || tex != null) 39 { 40 if (dc == null) 41 {
                // 生成dc
42 dc = UIDrawCall.Create(this, mat, tex, sdr); 43 dc.depthStart = w.depth; 44 dc.depthEnd = dc.depthStart; 45 dc.panel = this; 46 47 } 48 else 49 {
                // 合并dc
50 int rd = w.depth; 51 if (rd < dc.depthStart) dc.depthStart = rd; 52 if (rd > dc.depthEnd) dc.depthEnd = rd; 53 } 54 55 w.drawCall = dc; 56 57 if (generateNormals) w.WriteToBuffers(dc.verts, dc.uvs, dc.cols, dc.norms, dc.tans); 58 else w.WriteToBuffers(dc.verts, dc.uvs, dc.cols, null, null); 59 } 60 } 61 else w.drawCall = null; 62 } 63 64 if (dc != null && dc.verts.size != 0) 65 { 66 drawCalls.Add(dc);
         // 绘制dc
67 dc.UpdateGeometry(); 68 } 69 }

 

在NGUI中所有的UI组件都是继承自UIwidget这个容器;在UIwidget组件中可以看见他维护了这样几个属性:材质,贴图,以及shader,还有该容器所属的UIpanel和该容器的Drawcall;

  

 1 public UIPanel panel;
 2 public UIDrawCall drawCall;
 3 
 4 public virtual Material material
 5     {
 6         get
 7         {
 8             return null;
 9         }
10         set
11         {
12             throw new System.NotImplementedException(GetType() + " has no material setter");
13         }
14     }
15 
16 public virtual Texture mainTexture
17     {
18         get
19         {
20             Material mat = material;
21             return (mat != null) ? mat.mainTexture : null;
22         }
23         set
24         {
25             throw new System.NotImplementedException(GetType() + " has no mainTexture setter");
26         }
27     }
28 
29 public virtual Shader shader
30     {
31         get
32         {
33             Material mat = material;
34             return (mat != null) ? mat.shader : null;
35         }
36         set
37         {
38             throw new System.NotImplementedException(GetType() + " has no shader setter");
39         }
40     }
41 
42 virtual public void OnFill(BetterList<Vector3> verts, BetterList<Vector2> uvs, BetterList<Color32> cols)
43     {
44         // Call this in your derived classes:
45         //if (onPostFill != null)
46         //    onPostFill(this, verts.size, verts, uvs, cols);
47     }

材质,贴图,以及shader,还有该容器所属的UIpanel和该容器的Drawcall;

以及一个虚函数OnFill;这些是对渲染来说是主要的属性;

  而将特效层级插入的思路则是给特效上添加一个widget组件并归入NGUI渲染排序中,这样就可以和讨巧的去管理整个渲染顺序:

首先新建一个继承自UIWidget的UINGUIEffect组件:

  1 using UnityEngine;
  2 using System.Collections;
  3 
  4 // 该组件必须有渲染组件
  5 [RequireComponent(typeof(Renderer))]
  6 public class UINGUIEffect : UIWidget {
  7     // 维护材质 贴图 以及 shader 
  8     private Material mMaterial;
  9     private Texture mMainTexture;
 10     private Shader mShader;
 11     private Renderer mRender;
 12 
 13     // 重写
 14     public override Material material
 15     {
 16         get
 17         {
 18             return mMaterial;
 19         }
 20 
 21         set
 22         {
 23             mMaterial = value;
 24         }
 25     }
 26 
 27     public override Shader shader
 28     {
 29         get
 30         {
 31             return mShader;
 32         }
 33 
 34         set
 35         {
 36             mShader = value;
 37         }
 38     }
 39 
 40     public override Texture mainTexture
 41     {
 42         get
 43         {
 44             return mMainTexture;
 45         }
 46 
 47         set
 48         {
 49             mMainTexture = value;
 50         }
 51     }
 52 
 53     protected override void Awake()
 54     {
 55         if (GetComponent<Renderer>())
 56         {
 57             mRender = GetComponent<Renderer>();
 58             mMaterial = mRender.sharedMaterial;
 59             mMainTexture = mRender.sharedMaterial.mainTexture;
 60             mShader = mRender.sharedMaterial.shader;
 61         }
 62         // 这里缓存设置Drawcall渲染层级时的回调
 63         onRenderQueueChanged = OnRQChanged;
 64         base.Awake();
 65     }
 66 
 67     void OnRQChanged(int rq)
 68     {
 69         // 回调指定该渲染层级
 70         GetComponent<Renderer>().sharedMaterial.renderQueue = rq;
 71      
 72     }
 73 
 74     protected override void OnInit()
 75     {
 76         base.OnInit();
 77     }
 78 
 79     protected override void OnStart()
 80     {
 81         base.OnStart();
 82     }
 83 
 84     protected override void OnEnable()
 85     {
 86         base.OnEnable();
 87     }
 88 
 89     protected override void OnDisable()
 90     {
 91         base.OnDisable();
 92     }
 93 
 94     protected override void OnUpdate()
 95     {
 96         base.OnUpdate();
 97     }
 98 
 99     public override void OnFill(BetterList<Vector3> verts, BetterList<Vector2> uvs, BetterList<Color32> cols)
100     {
101        // 创建一个空四边形占据一个dc;如过这里是空的话该组件就不会生成dc所以必须有一个;
102         verts.Add(new Vector3(1, 0, 1));
103         verts.Add(new Vector3(1, 0, -1));
104         verts.Add(new Vector3(-1, 0, 1));
105         verts.Add(new Vector3(-1, 0, -1));
106 
107         uvs.Add(new Vector2(1, 1));
108         uvs.Add(new Vector2(1, 0));
109         uvs.Add(new Vector2(0, 1));
110         uvs.Add(new Vector2(0, 0));
111 
112         cols.Add(new Color32(255,255,255, 255));
113         cols.Add(new Color32(255, 255, 255, 255));
114         cols.Add(new Color32(255, 255, 255, 255));
115         cols.Add(new Color32(255, 255, 255, 255));
116 
117         base.OnFill(verts, uvs, cols);
118         if (onPostFill != null)
119             onPostFill(this, verts.size, verts,uvs,cols);
120     }
121 }

因此NGUi代码就需要稍作需改:

//添加委托
public delegate void OnRenderQueueChanged(int renderQueue);

//在UIWidget 以及UIdrawcall中增加委托

public OnRenderQueueChanged onRenderQueueChanged;

//在UIPanel中FillAllDrawCalls方法中生成Drawcall时将widget维护的委托赋给它的dc

if (mat != null || sdr != null || tex != null)
                {
                    if (dc == null)
                    {
                        dc = UIDrawCall.Create(this, mat, tex, sdr);
                        dc.depthStart = w.depth;
                        dc.depthEnd = dc.depthStart;
                        dc.panel = this;
// 赋值委托
                        dc.onRenderQueueChanged = w.onRenderQueueChanged;
                    }

//最后在UIdrawcall设置renderQueque时调用委托设置特效层级

    public int renderQueue
    {
        get
        {
            return mRenderQueue;
        }
        set
        {
            if (mRenderQueue != value)
            {
                mRenderQueue = value;
                // 调用回调设置特效层级
                if (onRenderQueueChanged != null)
                    onRenderQueueChanged(mRenderQueue);

                if (mDynamicMat != null)
                {
                    mDynamicMat.renderQueue = value;
#if UNITY_EDITOR
                    if (mRenderer != null) mRenderer.enabled = isActive;
#endif
                }
            }
        }
    }

这样特效的层级就可以归入NGUI的渲染层级管理中了

NGUI中穿插粒子或者mesh渲染层级

NGUI中穿插粒子或者mesh渲染层级

 

优化:在一些共享材质的效果上会引起渲染混乱所以在Awake的时候复制一个材质避免影响其他界面显示:

 1  protected override void Awake()
 2     {
 3         if (GetComponent<Renderer>())
 4         {
 5             mRender = GetComponent<Renderer>();
 6             mMaterial = new Material(mRender.sharedMaterial) ;
 7             GetComponent<Renderer>().sharedMaterial = mMaterial;
 8             mMainTexture = mMaterial.mainTexture;
 9             mShader = mMaterial.shader;
10         }
11         onRenderQueueChanged = OnRQChanged;
12         base.Awake();
13     }
14 
15     void OnRQChanged(int rq)
16     {
17         if (!gameObject.activeSelf) return;
18         mMaterial.renderQueue = 0;
19         mMaterial.renderQueue = rq;
20     }

 

这是一个较为粗糙的做法,还有很多不足,如果有更好的做法还请留言相告谢谢!!!!好了回去撸代码了

转载于:https://www.cnblogs.com/smallboat/p/5999784.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/108807.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 汇编工具

    汇编工具【常见的基本汇编书籍】《Windows.环境下32位汇编语言程序设计(第2版)》《汇编语言编程艺术》《Intel汇编语言程序设计(第四版)》《Intel汇编语言程序设计(第五版)范例》《80×86汇编语言程序设计教程》《IBM.PC.汇编语言程序设计(第五版)》《MicrosoftMASM手册》《Intel®64andIA-32Arch…

    2022年10月11日
  • 西班牙语dele等级_DELE——西班牙语水平考试

    西班牙语dele等级_DELE——西班牙语水平考试西班牙语的等级考试在我国发展比较晚,自2004年起我国教育部才开始组织。而且国内的西班牙语等级考试的对象仅为在校西班牙语专业的本科生,每年5月左右考试。水平测试相当于英语四级。另外职称外语考试中有西班牙语的考试,外国学生进入公立大学须通过西班牙语国家等级考试和大学入学考试。DELE简介:作为一门外语的西班牙语水平测试:DELE(DiplomasdeEspa?olComoLenguaEx…

  • 参数化(二):执行查询的方式

    参数化(二):执行查询的方式

    2021年11月26日
  • L05 Laravel 教程 – 电商实战

    L05 Laravel 教程 – 电商实战

    2021年10月26日
  • Activity 工作流引擎[通俗易懂]

    Activity 工作流引擎[通俗易懂]Activiti工作流引擎使用详解http://blog.csdn.net/m0_37327416/article/details/71743368Activity用户手册http://www.mossle.com/docs/activiti/index.html#demo.setup.one.minute.version学习视频https://item.taobao

  • CentOS8国内镜像下载地址

    CentOS8国内镜像下载地址目录CentOS介绍CentOSLinux和CentOSStream区别镜像下载说明CentOS介绍CentOS是基于RedHatEnterpriseLinux(RHEL/业界最知名的发行版)源代码再编译出来的免费版,因此不仅继承RHEL优越的稳定性(与Debian不分上下),还提供免费更新,因此在服务器提供商、中小型公司中装机量几乎是最大最流行的Linux系统,现在也已正式加入红帽公司。从事互联网技术的同学,CentOS应该是值得你深入了解学习研究的……Ce

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号