NGUI源码分析(一) 核心类UIDrawCall

前阵子一直想研究一下NGUI的源码,打开一看代码很多代码很庞大不知道从何入手,然后我看代码的方法搞错了,总想一下子就把类之间的关系理清楚,看到局部的代码没看懂又老是不自觉的沉陷其中,结果是这里看懂一点,那里又没看懂,搞的我一知半解又一头雾水,结果我放弃了。后来无意中有个网友告诉我,研究代码一开始不能思路铺的太开,一开始应该从最核心的部分看起,然后一层一层的向外围展开,一次只看一个类或一个方法,别想看A的时候又想看B,遇到不懂的时候可以先放着,特别时遇到很复杂的调用关系的代码时千万不要深陷其中。之后我完全按照这个网友的建议,从最核心的一小部分开始着手,比如我看DrawCall 类的时候完全不管Widget和Panel,我只关心这个类对外开放什么接口,需要什么数据等等,结果发现这种方法效果奇佳。

     废话不多说切入正题,DrawCall是NGUI最核心的一个类,它负责把顶点,UV,颜色等数据输入到网格和构建材质,最终绘制出我们看到的UI图形.

  下面是UIDrawCall的关键方法的介绍:

  一.UpdateGeometry() 最核心最重要的方法, 通过顶点,UV,颜色,贴图等信息绘制UI图形,下面是部分关键的代码:

    1.if (mFilter == null) mFilter = gameObject.AddComponent<MeshFilter>();//获得MeshFilter组件    
    2. mMesh = new Mesh(); //创建用来渲染的网格对象 
    3. mTriangles = (verts.size >> 1); //三角形数量=顶点数/2
    4.  mMesh.vertices = verts.buffer; //将顶点 UV 颜色信息赋值跟网格对象,将网格赋值给mFilter 
            mMesh.uv = uvs.buffer;
            mMesh.colors32 = cols.buffer;
            mFilter.mesh = mMesh;
    5.if (mRenderer == null) mRenderer = gameObject.GetComponent<MeshRenderer>();//获得MeshRenderer组件
    6.UpdateMaterials();//更新Material 完成一次drawcall

  三.UpdateMaterials() 更新Material

void UpdateMaterials ()
{
    //如没有材质或使用了裁剪,就需要重建材质
    if (mRebuildMat || mDynamicMat == null || mClipCount != panel.clipCount)
    {
        RebuildMaterial();
        mRebuildMat = false;
    }
    else if (mRenderer.sharedMaterial != mDynamicMat)
    {
        //将材质赋值给MeshRender组件 ,更新render
        mRenderer.sharedMaterials = new Material[] { mDynamicMat };
    }
}

三.RebuildMaterial ()重新生成材质
    

1. CreateMaterial(); // 创建新的材质对象
2. if (mTexture != null) mDynamicMat.mainTexture = mTexture;//将纹理赋值给材质
3. if (mRenderer != null) mRenderer.sharedMaterials = new Material[] { mDynamicMat };//将材质赋值给MeshRender组件 ,更新render

四.CreateMaterial()  创建新的材质 

1. string shaderName = (mShader != null) ? mShader.name :
((mMaterial != null) ? mMaterial.shader.name : "Unlit/Transparent Colored");//默认使用NGUI自带的shader
2. //如果裁剪数量不为0 获得裁剪相关的shader ,如果不需要裁剪,直接获得shader对象
    if (mClipCount != 0)
    {
        shader = Shader.Find("Hidden/" + shaderName + " " + mClipCount);
        if (shader == null) Shader.Find(shaderName + " " + mClipCount);

        // Legacy functionality
        if (shader == null && mClipCount == 1)
        {
            mLegacyShader = true;
            shader = Shader.Find(shaderName + soft);
        }
    }
    else shader = Shader.Find(shaderName);
3. mDynamicMat.shader = shader; //将shader赋值给Material对象

  其实DrawCall类功能很单一,下面做一个小测试,测试后会发现:完全可以把DrawCall类分离出NGUI,不用管Panel和Widget类,只用一个DrawCall类就可以独立渲染出想要的图形。

  下面是DrawCall测试的步骤:
  1.新建一个CustomDrawCall类,把UIDrawCall的代码原封不动的复制过去,把部分的属性改为Public属性:
       public Texture mTexture;
       [HideInInspector]
       public int[] mIndices;
  2.注释掉OnWillRenderObject()方法
  3.在unity3d场景中新建一个空GameObject,命名为“DrawCallObject”,这个对象就是我们绘制的目标对象。然后给这个对象添加MeshFilder,MeshRender组件,再挂上一个CustomDrawCall脚本,随便找一张贴图,拖到CustomDrawCall面板赋值给MTexture属性

   

         4.创建一个脚本TestDrawCall,在Start方法添加代码如下:

    5.把TestDrawCall脚本挂到场景的Main Camera上去

    6.运行Uinty3d,切换到场景,就可以看到贴图被绘制出来了:

    

   总结:UIDraw类其实并不复杂,它并不关心谁调用了它,我们完全可以把它独立出来,只要外部传入顶点,UV,颜色,贴图等信息给它,就可以绘制图形了。

   测试代码的链接是http://pan.baidu.com/s/1i3GRbtb

原文地址:http://www.cnblogs.com/rocky300/articles/4674046.html

猜你喜欢

转载自blog.csdn.net/Marccco/article/details/84637226