【NGUI源码剖析】深入理解NGUI的drawcall
来源:互联网 发布:淘宝实名认证小号购买 编辑:程序博客网 时间:2024/05/18 20:51
引言
上篇【NGUI源码剖析】NGUI的drawcall简单认识了NGUI中的drawcall。借着近来工作更替的间隙,本文在之前的基础上做一点深入的分析:
- UIPanel工作流程图
- 如何生成drawcall
- widgets的生成及作用
- drawcall的合并
UIPanel的工作流程
无论是UIDrawCall还是UIWidget的流程,都离不开UIPanel的工作流。“吾尝终日而思矣,不如须臾之所学也”看了几天NGUI的源代码,才发觉抓住主线才不会跑偏,而这幅图就是打开NGUI秘密的金钥匙。
如何生成drawcall
这里还是要从UIPanel中的数据drawCalls说起
/// <summary> /// List of draw calls created by this panel. Do not attempt to modify this list yourself. /// </summary> [System.NonSerialized] public List<UIDrawCall> drawCalls = new List<UIDrawCall>();
可以看到drawCalls.Add()的调用全都在FillAllDrawCalls()内部:
/// <summary> /// Fill the geometry fully, processing all widgets and re-creating all draw calls. /// </summary> void FillAllDrawCalls () { for (int i = 0; i < drawCalls.Count; ++i) UIDrawCall.Destroy(drawCalls[i]); drawCalls.Clear(); Material mat = null; Texture tex = null; Shader sdr = null; UIDrawCall dc = null; int count = 0; if (mSortWidgets) SortWidgets(); for (int i = 0; i < widgets.Count; ++i) { UIWidget w = widgets[i]; if (w.isVisible && w.hasVertices) { Material mt = w.material; if (onCreateMaterial != null) mt = onCreateMaterial(w, mt); Texture tx = w.mainTexture; Shader sd = w.shader; // 判断widgets[i-1]与widgets[i]的mateial,texture,shader是否一致 if (mat != mt || tex != tx || sdr != sd) { if (dc != null && dc.verts.Count != 0) { drawCalls.Add(dc); //缓存widgets[i-1]的drawcall dc.UpdateGeometry(count); dc.onRender = mOnRender; mOnRender = null; count = 0; dc = null; //缓存drawcall后,重置drawcall } //缓存widgets[i]的material,texture,shader mat = mt; tex = tx; sdr = sd; } if (mat != null || sdr != null || tex != null) { // 创建新的drawcall,设置drawcall相关的数据 if (dc == null) { dc = UIDrawCall.Create(this, mat, tex, sdr); dc.depthStart = w.depth; dc.depthEnd = dc.depthStart; dc.panel = this; dc.onCreateDrawCall = onCreateDrawCall; } //widgets[i-1]与widgets[i]的material,shader,texture相同时,共用一个drawcall else { // 更新drawcall的深度范围 int rd = w.depth; if (rd < dc.depthStart) dc.depthStart = rd; if (rd > dc.depthEnd) dc.depthEnd = rd; } w.drawCall = dc; ++count; if (generateNormals) w.WriteToBuffers(dc.verts, dc.uvs, dc.cols, dc.norms, dc.tans, generateUV2 ? dc.uv2 : null); else w.WriteToBuffers(dc.verts, dc.uvs, dc.cols, null, null, generateUV2 ? dc.uv2 : null); if (w.mOnRender != null) { if (mOnRender == null) mOnRender = w.mOnRender; else mOnRender += w.mOnRender; } } } else w.drawCall = null; } //缓存widgets[widgets.Count-1]的drawcall if (dc != null && dc.verts.Count != 0) { drawCalls.Add(dc); dc.UpdateGeometry(count); dc.onRender = mOnRender; mOnRender = null; } }
从代码中可以看到,新增drawcall主要通过缓存widgets[i-1]的material,texture,shader与widgets[i]进行对比。如果使用相同的material,texture,shader则共用同一个drawcall,否则新创建一个drawcall。
其中都是在遍历widgets进行操作,那么widgets从哪里来?又要到哪里去?
widgets的生成及作用
- UIWidget的定义
UIPanel与UIWidget的对应关系是一对多的,而UIWidget本质上是UISprite,UI2DSprite,UITexture,UILabel等几种不同的控件。
- widgets的生成
widgets.Add的调用有两处:
1.改变UIWidget的深度时
/// <summary> /// Depth controls the rendering order -- lowest to highest. /// </summary> public int depth { get { // Experiment with a transform-based depth, uGUI style //if (mDepth == int.MinValue) //{ // int val = cachedTransform.GetSiblingIndex(); // UIWidget pt = parent as UIWidget; // if (pt != null) val += pt.depth; // return val; //} return mDepth; } set { if (mDepth != value) { if (panel != null) panel.RemoveWidget(this); mDepth = value; if (panel != null) { panel.AddWidget(this); ...
2.创建UIPanel时
/// <summary> /// Ensure we have a panel referencing this widget. /// </summary> public UIPanel CreatePanel () { if (mStarted && panel == null && enabled && NGUITools.GetActive(gameObject)) { panel = UIPanel.Find(cachedTransform, true, cachedGameObject.layer); if (panel != null) { mParentFound = false; panel.AddWidget(this); CheckLayer(); Invalidate(true); } } return panel; }
drawcall的合并
从FillAllDrawCalls函数中看drawcall的生成过程,可以肯定的是
widgets.Count >= drawcalls.Count
如果符合【NGUI源码剖析】NGUI如何优化drawcall数量中drawcall的合并条件,这两个List变动的数量就是drawcall合并的数量。
参考文章:
NGUI所见即所得之深入剖析UIPanel,UIWidget,UIDrawCall底层原理
- 【NGUI源码剖析】深入理解NGUI的drawcall
- 【NGUI源码剖析】NGUI的drawcall
- 【NGUI源码剖析】NGUI如何优化drawcall数量
- 源码分析NGUI的DrawCall合并原理
- 源码分析NGUI的DrawCall合并原理
- NGUI诡异的drawCall
- NGUI DrawCall
- NGUI减少drawcall 的总结
- Unity3D:NGUI 深入剖析NGUI的游戏UI架构
- NGUI深入理解-----------------UIRoot
- NGUI深入理解
- NGUI深入理解-----------------UIAnchor
- NGUI深入理解-----------------UIStretch
- Unity3d NGUI的drawcall,UISprite与UITexture
- NGUI 减少drawcall
- NGUI 减少drawcall
- NGUI Drawcall 优化
- NGUI 减少drawcall
- <ul>标签的用法
- 问题 J: 二叉树的创建和文本显示
- Python 面向对象编程基础(定义类并创建实例、创建实例属性、初始化实例属性、访问限制、类属性、属性名冲突、实例方法、类方法)
- 【简记】Java Web 内幕——Spring中Bean的创建(源码摘录)
- Windows下的VPN连接设置图文教程
- 【NGUI源码剖析】深入理解NGUI的drawcall
- Android_常驻进程(杀不死的进程)
- 学习Weblogic时知识归纳(二)
- 【OpenCV入门指南】第一篇 安装OpenCV
- java设计模式之代理模式(动态代理和静态代理)
- c++日期类
- 单链表基础篇
- sql查询
- 利用OpenCV自带的haartraining程序训练分类器并测试