UGUI源碼分析:Graphic,UGUI中最重要的部分之一

系列

UGUI源碼分析系列總覽

Graphic

Related Class: Graphic、MaskableGraphic、GraphicRegistry、CanvasUpdateRegistry、VertexHelper

Related Interface: ICanvasElement、IMeshModifier、IClippable、IMaskable、IMaterialModifier

Intro: 圖形組件的基類,基礎中的基礎組件

  • ICanvasElement: Canvas元素(重建接口),當Canvas發生更新時重建(void Rebuild)
  • IMeshModifier:網格處理接口
  • IClippable:裁剪相關處理接口
  • IMaskable:遮罩處理接口
  • IMaterialModifier:材質處理接口

Graphic 作爲圖像組件的基類,主要實現了網格與圖像的生成/刷新方法。
在生命週期Enable階段、Editor模式下的OnValidate中、層級/顏色/材質改變時都會進行相應的刷新(重建)。
重建過程主要通過 CanvasUpdateSystem 最終被Canvas所重新渲染。
詳情請見:CanvasUpdateSystem源碼剖析

重建主要分爲兩個部分:頂點重建(UpdateGeometry)與 材質重建(UpdateMaterial)

更新完成的結果會設置進CanvasRenderer,從而被渲染形成圖像。

在這裏插入圖片描述

本章着重分析Graphic源碼部分,接下來的章節會重點分析Graphic繼承鏈下的MaskableGraphic與衍生出來的組件們。


GraphicRegistry

管理同Canvas下的所有Graphic對象

Dictionary<Canvas, IndexedSet<Graphic>> m_Graphics

Graphic 初始化時(Enable)會尋找其最近根節點的Canvas組件,並以此爲key存儲在GraphicRegistry中。


Rebuild

public virtual void Rebuild(CanvasUpdate update)
{
    if (canvasRenderer.cull)
        return;
    switch (update)
    {
        case CanvasUpdate.PreRender:
            if (m_VertsDirty)
            {
                UpdateGeometry();//網格更新
                m_VertsDirty = false;
            }
            if (m_MaterialDirty)
            {
                UpdateMaterial();//材質紋理更新
                m_MaterialDirty = false;
            }
            break;
    }
}

UpdateGeometry

Graphic 頂點(網格)更新與生成,發生頂點重建時會被調用。

過程:

  • 更新VertexHelper數據
  • 遍歷身上的IMeshModifier組件(MeshEffect組件,實現網格的一些特效,例如Shadow、Outline),更新VertexHelper數據
  • 將最終的頂點數據設置給 workerMesh,並將workerMesh設置進canvasRenderer中,進行渲染。
private void DoMeshGeneration()
{
    if (rectTransform != null && rectTransform.rect.width >= 0 && rectTransform.rect.height >= 0)
        OnPopulateMesh(s_VertexHelper);//更新頂點信息
    else
        s_VertexHelper.Clear(); // clear the vertex helper so invalid graphics dont draw.

    var components = ListPool<Component>.Get();
    GetComponents(typeof(IMeshModifier), components);

    for (var i = 0; i < components.Count; i++)
        ((IMeshModifier)components[i]).ModifyMesh(s_VertexHelper);//若由網格特效,則由特效繼續更新頂點信息

    ListPool<Component>.Release(components);

    s_VertexHelper.FillMesh(workerMesh);
    canvasRenderer.SetMesh(workerMesh);//設置當canvasRenderer中
}

基礎的網格由 4 個頂點 2 個三角面構成

在這裏插入圖片描述

VertexHelper : 臨時存儲有關頂點的所有信息,輔助生成網格

- List<Vector3> m_Positions : 頂點位置

- List<Color32> m_Colors :頂點顏色

- List<Vector2> m_Uv0S :第1個頂點UV座標

- List<Vector2> m_Uv1 :第2個頂點UV座標

- List<Vector2> m_Uv2S :第3個頂點UV座標

- List<Vector2> m_Uv3S :第4個頂點UV座標

- List<Vector3> m_Normals :法線向量

- List<Vector4> m_Tangents : 切線向量

- List<int> m_Indices : 三角面頂點索引

BaseMeshEffect

  • PositionAsUV1: 根據頂點座標設置UV1座標(一般爲法線貼圖,不加此組件時UV1座標默認是Vector2.zero
  • Shadow:在頂點數基礎上增加了一倍的頂點數,並根據偏移(effectDistance)設置新頂點的座標,實現陰影效果。
  • Outline:繼承自Shadow,原理就是分別在四個角(根據effectDistance換算)上實現了四個Shadow,即增加了4倍的頂點數。

在這裏插入圖片描述


UpdateMaterial

Graphic 材質更新,發生材質重建時會被調用。

過程:

  • 獲取自身材質material,遍歷身上的IMaterialModifier組件(材質處理組件,實現材質特效,例如Mask),更新 materialForRendering
  • 將最終的材質數據materialForRendering與紋理mainTexture設置進canvasRenderer中,進行渲染。
protected virtual void UpdateMaterial()
{
    if (!IsActive())
        return;
    canvasRenderer.materialCount = 1;
    canvasRenderer.SetMaterial(materialForRendering, 0);
    canvasRenderer.SetTexture(mainTexture);
}

public virtual Material materialForRendering
{
    get
    {
        var components = ListPool<Component>.Get();
        GetComponents(typeof(IMaterialModifier), components);

        var currentMat = material;
        for (var i = 0; i < components.Count; i++)
            currentMat = (components[i] as IMaterialModifier).GetModifiedMaterial(currentMat);//這裏由IMaterialModifier組件對currentMat進行特效化處理,得到最終展示的材質
        ListPool<Component>.Release(components);
        return currentMat;
    }
}

.
.
.
.
.


嗨,我是作者Vin129,逐兒時之夢正在遊戲製作的技術海洋中漂泊。知道的越多,不知道的也越多。希望我的文章對你有所幫助:)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章