NGUI Drawcall 优化

来源:互联网 发布:手机音乐软件 编辑:程序博客网 时间:2024/06/05 14:18

NGUI 方面的Draw Call 优化:

(1)     打包图集

一、每个材质/纹理的渲染一定是会产生DrawCall的,这个DrawCall只能通过打包图集来进行优化。

二、从功能角度进行划分,例如UI可以划分为公共部分,以及每个具体的界面,功能上,显示上密切相关的图片打包到一起 

 

(2)渲染顺序

一、  U3D的渲染是有顺序的,NGUI的渲染顺序是由我们控制的,控制好NGUI的渲染顺序,你才能控制好DrawCall。

二、  一个DrawCall,表示U3D使用这个材质/纹理,来进行一次渲染,那么这次渲染假设有3个对象,那么当3个对象都使用这一个材质/纹理的时候,就会产生一次DrawCall。假设3个对象使用不同的材质/纹理,那么无疑会产生3个DrawCall。

 

例子:

A,B使用材质1,C使用材质2,这时候会有几个Draw Call?

 

有两种情况,3个Draw Call:

A:材质1

B:材质2

C:材质1

 

第二种情况,2个DrawCall

A:材质1

C:材质1

B:材质2

 

 

渲染顺序:Unity默认会按照控件的Depth来渲染。从后往前渲染,当使用相同材质的控件会合并为一个Draw Call。如果和前一个材质不相同则会重新产生一个Draw Call。所以会有上面两种不同的结果,如果同一个界面有更多的空间存在时,这个问题会更明显。在UI制作的时候就需要特别注意这一点。



NGUI为了减少GPU状态切换的消耗(比如切换material),把相同material的widget合并,减少DrawCall的数量。下文描述了NGUI如何对widget归类,以及减少DrawCall需要注意的地方。

归类widget的代码在UIPanel中的FillAllDrawCalls()里,代码如下

  1. void FillAllDrawCalls ()
  2.         {
  3.                 for (int i = 0; i < drawCalls.size; ++i)
  4.                         UIDrawCall.Destroy(drawCalls.buffer[i]);
  5.                 drawCalls.Clear();

  6.                 Material mat = null;
  7.                 Texture tex = null;
  8.                 Shader sdr = null;
  9.                 UIDrawCall dc = null;

  10.                 if (mSortWidgets) SortWidgets();

  11.                 for (int i = 0; i < widgets.size; ++i)
  12.                 {
  13.                         UIWidget w = widgets.buffer[i];

  14.                         if (w.isVisible && w.hasVertices)
  15.                         {
  16.                                 Material mt = w.material;
  17.                                 Texture tx = w.mainTexture;
  18.                                 Shader sd = w.shader;

  19.                                 if (mat != mt || tex != tx || sdr != sd)
  20.                                 {
  21.                                         if (mVerts.size != 0)
  22.                                         {
  23.                                                 SubmitDrawCall(dc);
  24.                                                 dc = null;
  25.                                         }

  26.                                         mat = mt;
  27.                                         tex = tx;
  28.                                         sdr = sd;
  29.                                 }

  30.                                 if (mat != null || sdr != null || tex != null)
  31.                                 {
  32.                                         if (dc == null)
  33.                                         {
  34.                                                 dc = UIDrawCall.Create(this, mat, tex, sdr);
  35.                                                 dc.depthStart = w.depth;
  36.                                                 dc.depthEnd = dc.depthStart;
  37.                                                 dc.panel = this;
  38.                                         }
  39.                                         else
  40.                                         {
  41.                                                 int rd = w.depth;
  42.                                                 if (rd < dc.depthStart) dc.depthStart = rd;
  43.                                                 if (rd > dc.depthEnd) dc.depthEnd = rd;
  44.                                         }

  45.                                         w.drawCall = dc;

  46.                                         if (generateNormals) w.WriteToBuffers(mVerts, mUvs, mCols, mNorms, mTans);
  47.                                         else w.WriteToBuffers(mVerts, mUvs, mCols, null, null);
  48.                                 }
  49.                         }
  50.                         else w.drawCall = null;
  51.                 }
  52.                 if (mVerts.size != 0) SubmitDrawCall(dc);
  53.         }
复制代码

算法描述如下

先把UIPanel中的Widget按depth从小到大排序,如果depth相同那按照material的ID来排序。然后遍历每个元素,把material相同的Widget归类到同一个drawCall。合并之后的结果如下图

最后生成了3个DrawCall,并按顺序提交GPU绘制。

为何要采用这个算法呢?因为NGUI的Material是透明材质,不会写入深度缓存(但是会进行深度测试,以保证与非透明物体的层次正确),我们可以看NGUI材质所使用的Unlit/Transparent Colored这个Shader,里面有一句ZWrite Off。所以widget的前后关系与z坐标是没有关系的,而是与DrawCall的绘制顺序有关。所以如果要按照上图的depth来显示widget,必然只能分成3个DrawCall,并且按顺序绘制。


原文地址:

http://www.cnblogs.com/Oceanou/p/4001650.html

http://bbs.9ria.com/thread-282804-1-1.html

0 0
原创粉丝点击