NGUI源码分析(五) UIPanel

来源:互联网 发布:在jsp中写java代码 编辑:程序博客网 时间:2024/06/17 12:22

UIPanel可以看成一个集合,一个Panel可以包含多个Widget.负责排序和更新widget,同时控制widget在什么时候绘制图形。下面具体看看是如何实现的.

一.重要属性:

static public List<UIPanel> list = new List<UIPanel>();  //保存所有的panel
 
public RenderQueue renderQueue = RenderQueue.Automatic;//渲染次序类型
public int startingRenderQueue = 3000;//渲染顺序值得
 
public List<UIWidget> widgets = new List<UIWidget>(); //保存当前panel的所有widget
 
public List<UIDrawCall> drawCalls = new List<UIDrawCall>();//当前panel所有的drawCall
  
int mDepth = 0;//深度
 
int mSortingOrder;//队列排序值
 
 bool mRebuild = false;//重要属性 如果为true需要重构所有的DrawCall. Panel中的OnEnable,RemoveWidget,AddWidget等这几个方法和改变Widget深度会设置mRebuild为true
 
二.重要方法:
void LateUpdate () //核心方法 更新所有Panel和DrawCall
    //每帧只执行一次
    if (mUpdateFrame != Time.frameCount) 
    {
       mUpdateFrame = Time.frameCount;
 
       // 按顺序更新每一个Panel
       for (int i = 0, imax = list.Count; i < imax; ++i)
            list[i].UpdateSelf();
    }
   
   //初始渲染次序
   int rq = 3000;
 
   //更新所有DrawCall
   for (int i = 0, imax = list.Count; i < imax; ++i)
   {
        UIPanel p = list[i];
       
        //如果渲染次序设置为Automatic 则渲染顺序是从底层开始往上
        if (p.renderQueue == RenderQueue.Automatic)
        {
             p.startingRenderQueue = rq;
            //
             p.UpdateDrawCalls();
             rq += p.drawCalls.Count;
        }
        //如果渲染次序设置为StartAt 则渲染顺序值为默认值3000 下一个从3000+ p.drawCalls.Count 开始
        else if (p.renderQueue == RenderQueue.StartAt)
        {
             p.UpdateDrawCalls();
             if (p.drawCalls.Count != 0)
             rq = Mathf.Max(rq, p.startingRenderQueue + p.drawCalls.Count);
        }
        else //如果渲染次序设置为Explicit 下一个从startingRenderQueue + 1开始
        {
             p.UpdateDrawCalls();
             if (p.drawCalls.Count != 0)
              rq = Mathf.Max(rq, p.startingRenderQueue + 1);
        }
    }
 
void UpdateSelf () 方法:
    //更新矩阵变化
    UpdateTransformMatrix(); 
    //更新所有层
    UpdateLayers();
    //更新所有Widget 负责计算
    UpdateWidgets();
 
    //是否重建
    if (mRebuild) 
    {
       mRebuild = false;
       //重建所有的DrawCall
       FillAllDrawCalls();
    }
    else
    {
       for (int i = 0; i < drawCalls.Count; )
       {
            UIDrawCall dc = drawCalls[i];
           
            //如果DrawCall被标记为脏的 或者没有找到任何Widget使用这个DrawCall,就销毁这个DrawCall
            if (dc.isDirty && !FillDrawCall(dc))
            {
                 UIDrawCall.Destroy(dc);
                 drawCalls.RemoveAt(i);
                 continue;
            }
 
            ++i;
     }
 
UpdateLayers ()  更新层
  // 判断当前的层 是否跟GameObject的层一致 (可以在Inspector里设置)
 // 如果不一致则设置到GameObject所在的层 Panel下所有的Widget也设置到该层
  if (mLayer != cachedGameObject.layer)
  {
       mLayer = mGo.layer;
       UICamera uic = UICamera.FindCameraForLayer(mLayer);
       mCam = (uic != null) ? uic.cachedCamera : NGUITools.FindCameraForLayer(mLayer);
       NGUITools.SetChildLayer(cachedTransform, mLayer);
 
       for (int i = 0; i < drawCalls.Count; ++i)
        drawCalls[i].gameObject.layer = mLayer;
   }
 
 UpdateWidgets() 更新所有属于这个Panel的Widget
     //遍历Widget
    for (int i = 0, imax = widgets.Count; i < imax; ++i) 
    {
        UIWidget w = widgets[i];
           
        .......中间省略
        
        //更新Widget的顶点信息 在这篇NGUI源码分析(二) UIWidget文章提到过UpdateGeometry这个方法
        if (w.UpdateGeometry(frame))
        {
             changed = true;
 
             if (!mRebuild)
             {
                  if (w.drawCall != null)
                 {
                      //如果一个Widget发生改变 这个drawCall就会设置为脏 会导致FillDrawCall重新调用WriteToBuffers和dc.UpdateGeometry()
                       w.drawCall.isDirty = true;
                  }
                else
                {
                       //查找材质和贴图一样的DrawCall
                       FindDrawCall(w);
                 }
              }
    }
 
  FillAllDrawCalls()方法 重建所有的DrawCall,步骤:先清空所有的DrawCall 再创建所有Widget的DrawCall, 将Widget顶点填充到DrawCall,执行DrawCall绘制
Material,Texture,Shader都相同而且Widget的层次相同或相邻的话DrawCall会合并。代码太长这里就不贴出来了。
  总结:添加和删除Widget可能会导致所有DrawCall重构,改变Widget的深度会导致所有DrawCall重构,建议不要过于频繁添加,删除Widget和修改Widget的层次.一个Widget发生改变会导致其他使用相同DrawCall的Widget重新填充顶点到DrawCall,并绘制一次该DrawCall。DrawCall合并规则有两条,一是Material,Texture,Shader都相同,二是Widget的层必须相同或相邻。

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

0 0
原创粉丝点击