public abstract class Graphic: UIBehaviour,ICanvasElement

抽象类,继承自UIBehaviour,实现了一个接口

这里主要看一下他的生命周期

OnEnable

        protected override void OnEnable()
        {
            base.OnEnable();
            // 从父节点中获取Canvas,并缓存
            CacheCanvas();
            // 把自身缓存到Graphic管理器
            GraphicRegistry.RegisterGraphicForCanvas(canvas, this);

#if UNITY_EDITOR
    		// 编辑器方法,忽略忽略
            GraphicRebuildTracker.TrackGraphic(this);
#endif
            if (s_WhiteTexture == null)
                s_WhiteTexture = Texture2D.whiteTexture;

            SetAllDirty();
        }

Graphic管理器,Grphic的生命周期中,会把自身缓存到这两个字典,其中key是Graphic所属的Canvas

public class GraphicRegistry
{
    private static GraphicRegistry s_Instance;

    private readonly Dictionary<Canvas, IndexedSet<Graphic>> m_Graphics = new Dictionary<Canvas, IndexedSet<Graphic>>();
    private readonly Dictionary<Canvas, IndexedSet<Graphic>> m_RaycastableGraphics = new Dictionary<Canvas, IndexedSet<Graphic>>();
	
    ...
}

s_WhiteTexture是一个静态Tex2D,就是公共的默认贴图,比如Image默认会是一张白图,就是它

static protected Texture2D s_WhiteTexture = null;

OnDisable

        protected override void OnDisable()
        {
#if UNITY_EDITOR
            GraphicRebuildTracker.UnTrackGraphic(this);
#endif
            // 从相关管理器中删除自身
            GraphicRegistry.UnregisterGraphicForCanvas(canvas, this);
            CanvasUpdateRegistry.UnRegisterCanvasElementForRebuild(this);

            if (canvasRenderer != null)
                canvasRenderer.Clear();

            // 标记自身的rect为重构,不需要标记graphic,因为已经disable了
            LayoutRebuilder.MarkLayoutForRebuild(rectTransform);

            base.OnDisable();
        }

OnRectTransformDimensionsChange

当rect的大小发生变化时,如果Canvas正在重建,那么只重建顶点,否则重建顶点和布局

protected override void OnRectTransformDimensionsChange()
{
    if (gameObject.activeInHierarchy)
    {
        if (CanvasUpdateRegistry.IsRebuildingLayout())
            SetVerticesDirty();
        else
        {
            SetVerticesDirty();
            SetLayoutDirty();
        }
    }
}

TransformParentChanged

父节点改变,类似于先Disable再Enable

protected override void OnBeforeTransformParentChanged()
{
    GraphicRegistry.UnregisterGraphicForCanvas(canvas, this);
    LayoutRebuilder.MarkLayoutForRebuild(rectTransform);
}

protected override void OnTransformParentChanged()
{
    base.OnTransformParentChanged();

    m_Canvas = null;

    if (!IsActive())
        return;

    CacheCanvas();
    GraphicRegistry.RegisterGraphicForCanvas(canvas, this);
    SetAllDirty();
}

OnCanvasHierarchyChanged

当Canvas的状态发生变化时候,重新注册一下就行了

protected override void OnCanvasHierarchyChanged()
{
    // Use m_Cavas so we dont auto call CacheCanvas
    Canvas currentCanvas = m_Canvas;

    // Clear the cached canvas. Will be fetched below if active.
    m_Canvas = null;

    if (!IsActive())
        return;

    CacheCanvas();

    if (currentCanvas != m_Canvas)
    {
        GraphicRegistry.UnregisterGraphicForCanvas(currentCanvas, this);

        // Only register if we are active and enabled as OnCanvasHierarchyChanged can get called
        // during object destruction and we dont want to register ourself and then become null.
        if (IsActive())
            GraphicRegistry.RegisterGraphicForCanvas(canvas, this);
    }
}

Rebuild

实现自接口ICanvasElement,会在CanvasUpdateRegistry的PerformUpdate中被调用

根据渲染阶段进行重构

public virtual void Rebuild(CanvasUpdate update)
{
    if (canvasRenderer == null || canvasRenderer.cull)
        return;

    switch (update)
    {
        case CanvasUpdate.PreRender:
            if (m_VertsDirty)
            {
                UpdateGeometry();
                m_VertsDirty = false;
            }
            if (m_MaterialDirty)
            {
                UpdateMaterial();
                m_MaterialDirty = false;
            }
            break;
    }
}

UpdateGeometry

protected virtual void UpdateGeometry()
{
    // 这个bool会在不同的类里自己赋值,比如Image会在创建时设置为false,我们就看else里的方法就行
    if (useLegacyMeshGeneration)
    {
        DoLegacyMeshGeneration();
    }
    else
    {
        DoMeshGeneration();
    }
}

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.

    // 拿到IMeshModifier接口并调用,需要修改顶点信息的组件会实现这个接口,比如Outline
    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);

    // 将数据暂存到Mesh里
    s_VertexHelper.FillMesh(workerMesh);
    // 把Mesh交给Render,下一帧渲染,这是个C++方法
    canvasRenderer.SetMesh(workerMesh);
}

OnPopulateMesh

protected virtual void OnPopulateMesh(VertexHelper vh)
{
    // 返回一个rect
    var r = GetPixelAdjustedRect();
    var v = new Vector4(r.x, r.y, r.x + r.width, r.y + r.height);

    Color32 color32 = color;
    vh.Clear();
    // 添加4个顶点,就是rect的四个角,第三个参数是UV
    vh.AddVert(new Vector3(v.x, v.y), color32, new Vector2(0f, 0f));
    vh.AddVert(new Vector3(v.x, v.w), color32, new Vector2(0f, 1f));
    vh.AddVert(new Vector3(v.z, v.w), color32, new Vector2(1f, 1f));
    vh.AddVert(new Vector3(v.z, v.y), color32, new Vector2(1f, 0f));
	// 添加三角形面片
    vh.AddTriangle(0, 1, 2);
    vh.AddTriangle(2, 3, 0);
}

UpdateMaterial

这个就比较简单了,只是把自己的材质和贴图都赋值给Render

protected virtual void UpdateMaterial()
{
    if (!IsActive())
        return;

    canvasRenderer.materialCount = 1;
    canvasRenderer.SetMaterial(materialForRendering, 0);
    canvasRenderer.SetTexture(mainTexture);
}