博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
NGUI渲染流程
阅读量:6974 次
发布时间:2019-06-27

本文共 5695 字,大约阅读时间需要 18 分钟。

1

070534332335626.jpg

NGUI的渲染流程其实就是把Widget组件生成Mesh所需要的缓存数据,然后生成对应的DrallCall组合对应数据,生成渲染需要的Mesh数据,提交渲染。

Widget(数据)

UIGeometry被UIWidget实例化之后,通过UIWidget的子类,也就是UISprit,UILabel等,在OnFill()函数里算出所需的Geometry缓存(顶点数,UV,Color,法线,切线), 参考Sprite的Fill函数为例,根据Widget的绘制区域、颜色、UV等信息生产顶点、uv、颜色信息,必要的时候其实还会生成法线信息。其他组件类似,但是计算方式差异比较大。

void SimpleFill (BetterList
verts, BetterList
uvs, BetterList
cols) { Vector4 v = drawingDimensions; Vector4 u = drawingUVs; Color gc = drawingColor; Color lc = gc.GammaToLinearSpace(); verts.Add(new Vector3(v.x, v.y)); verts.Add(new Vector3(v.x, v.w)); verts.Add(new Vector3(v.z, v.w)); verts.Add(new Vector3(v.z, v.y)); uvs.Add(new Vector2(u.x, u.y)); uvs.Add(new Vector2(u.x, u.w)); uvs.Add(new Vector2(u.z, u.w)); uvs.Add(new Vector2(u.z, u.y)); if (!mApplyGradient) { cols.Add(lc); cols.Add(lc); cols.Add(lc); cols.Add(lc); } else { AddVertexColours(cols, ref gc, 1, 1); AddVertexColours(cols, ref gc, 1, 2); AddVertexColours(cols, ref gc, 2, 2); AddVertexColours(cols, ref gc, 2, 1); } }

UIPanel(管理)

Panel相当于一个容器管理单元,负责下面Widget组件列表和DrallCall组件列表的维护和协调工作,其主要工作,监视Widget的修改、如果修改则修改DrawCall的数据,必要的时候会重建全部DrallCall。对于每个DrallCall而言,则根据widget填充顶点、uv、颜色等数据到自己缓冲中

对于所有Widget组件,UIPanel通过遍历自己子类下所有的UIWidget组件(已经按深度排序),先创建一个UIDrawCall,然后把该Widget的material,texture,shader对象以及Geometry的缓存传给UIDrawCall,如此反复循环搜索该UIPanel下的每一个Widget,只要是material,texture,shader都和上一个Widget一样的Widget,他们的缓存都传给同一个UIDrawCall,直到循环结束或者碰到一个材质球,贴图,shader对象任一不相同的Widget。当遇到这种Widget,循环会再创建一个新的UIDrawCall,然后传递material,texture,shader,缓存,如此这般,直到循环完全结束。具体可以参考函数

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;                Texture tx = w.mainTexture;                Shader sd = w.shader;                if (mat != mt || tex != tx || sdr != sd)                {                    if (dc != null && dc.verts.size != 0)                    {                        drawCalls.Add(dc);                        dc.UpdateGeometry(count);                        dc.onRender = mOnRender;                        mOnRender = null;                        count = 0;                        dc = null;                    }                    mat = mt;                    tex = tx;                    sdr = sd;                }                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;                    }                    else                    {                        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);                    else w.WriteToBuffers(dc.verts, dc.uvs, dc.cols, null, null);                    if (w.mOnRender != null)                    {                        if (mOnRender == null) mOnRender = w.mOnRender;                        else mOnRender += w.mOnRender;                    }                }            }            else w.drawCall = null;        }        if (dc != null && dc.verts.size != 0)        {            drawCalls.Add(dc);            dc.UpdateGeometry(count);            dc.onRender = mOnRender;            mOnRender = null;        }    }

UIDrallCall

创建

对于每一个

更新

DrawCall其实就是在必要的时候根据组件数据生成对应的Mesh以及渲染相关的组件,其核心在UpdataGeometry()函数, 在该函数中做了一些几个事情:

  • 创建Mesh
if (mMesh == null)    {        mMesh = new Mesh();        mMesh.hideFlags = HideFlags.DontSave;        mMesh.name = (mMaterial != null) ? "[NGUI] " +            mMaterial.name : "[NGUI] Mesh";        mMesh.MarkDynamic();        setIndices = true;    }
  • 填充顶点数据
mMesh.vertices = verts.buffer;mMesh.uv = uvs.buffer;mMesh.colors32 = cols.buffer;if (norms != null) mMesh.normals = norms.buffer;if (tans != null) mMesh.tangents = tans.buffer;if (setIndices){    mIndices = GenerateCachedIndexBuffer(count, indexCount);    mMesh.triangles = mIndices;}
  • 更新材质
UpdateMaterials();

DrawCall在什么时候更新呢?

UIDrawCall.UpdateGeometry()函数仅有在Panel.FillDrawCall()和Panel.FillAllDrawCalls ()被调用因为每个DrawCall之对应一个Mesh,如果该DrawCall所属的Widget有改动,那么这个DrawCall就要通过UpdateGeometry修改新传入的缓存重绘才能更新效果。

UIPanel.FillAllDrawCalls()调用的话基本是整个Panel重绘了,还好调用条件比较苛刻,除了第一次LateUpdate,之后若有新的Widget加入进来,并且深度不在之前DrallCall的范围内,或者用了新的matiral shader texture那么就会影响之前已经布好的UI秩序,就会被重绘,调用的时候性能会损失很大。说简单点,就是当有可能需要生成新的UIDrawCall或者剔除UIDrawCall的时候,就会触发这个函数,这个机制,和之前遍历Widget来生成DrawCall的原理以及目的都是一样的。

UIPanel.FillDrawCall(UIDrawCall dc) 填充单独的DrawCall.一般只有少量的widget更新的时候 没必要更新所有的DrawCall(比如Label上的text有变化),只更新对应widget的DrawCall就好了.FillDrawCall()唯一的执行条件就是该DrawCall的isDirty为true,isDirty被切换为true的条件有三大类:1.widget上的视觉组件被更新,调用widget.MarkAsChanged();2.widget的忽然被添加删除和移动;3.Panel的ALPHA被改动;

引用

以下讨论基于NGUI3.8版本,后续版本代码可能进行了修改

转载地址:http://fpesl.baihongyu.com/

你可能感兴趣的文章
JDOM入门实例:读取与创建xml文档
查看>>
Knockout 新版应用开发教程之"text"绑定
查看>>
Android 分享微信好友 朋友圈
查看>>
java内存分配研究
查看>>
第 25 章 Munin
查看>>
【iOS】在Swift中使用JSONModel
查看>>
Node.js与Sails~Model数据模型
查看>>
Swift Internal Parameter and External Parameter 外部参数和内部参数
查看>>
DDD~领域层
查看>>
冷备份校验和恢复
查看>>
RedHat 6.8 内核编译
查看>>
I.MX6 Android 设备节点权限
查看>>
mysql中order by 和limit一起使用不当会导致效率极慢的4种优化方法
查看>>
您的Docker 容器还健康吗?一条简单命令帮您找出答案 [转载]
查看>>
WPF自定义控件与样式(14)-轻量MVVM模式实践
查看>>
HDD-FAT32 ZIP-FAT32
查看>>
当iPhone用上联发科,你还会爱上它吗?
查看>>
HDOJ(HDU) 1491 Octorber 21st
查看>>
ThinkPhp学习05
查看>>
Tomcat内核之ASCII解码的表驱动模式
查看>>