UGUI——Graphic

我的notion笔记

在这里插入图片描述

Base class for all visual UI Component When creating visual UI components you should inherit from this class.

继承自ICanvasElement,ICanvasElement接口用在CanvasUpdateRegistry类中,在PerformUpdate(canvas的willRenderCanvases)时负责对注册的该类组件进行rebuild LayoutComplete GraphicUpdateComplete

/// <summary>
/// This is an element that can live on a Canvas.
/// </summary>
public interface ICanvasElement
{
    /// <summary>
    /// Rebuild the element for the given stage.
    /// </summary>
    /// <param name="executing">The current CanvasUpdate stage being rebuild.</param>
    void Rebuild(CanvasUpdate executing);

    /// <summary>
    /// Get the transform associated with the ICanvasElement.
    /// </summary>
    Transform transform { get; }

    /// <summary>
    /// Callback sent when this ICanvasElement has completed layout.
    /// </summary>
    void LayoutComplete();

    /// <summary>
    /// Callback sent when this ICanvasElement has completed Graphic rebuild.
    /// </summary>
    void GraphicUpdateComplete();

    /// <summary>
    /// Used if the native representation has been destroyed.
    /// </summary>
    /// <returns>Return true if the element is considered destroyed.</returns>
    bool IsDestroyed();
}

protected Material m_Material;

默认材质球

private Color m_Color = Color.white;

Base color of the Graphic. The builtin UI Components use this as their vertex color. Use this to fetch or change the Color of visual UI elements, such as an Image.

public virtual Color color { get { return m_Color; } set { if (SetPropertyUtility.SetColor(ref m_Color, value)) SetVerticesDirty(); } }

private bool m_RaycastTarget = true

是否考虑射线检测

 /// <summary>
/// Should this graphic be considered a target for raycasting?
/// </summary>
public virtual bool raycastTarget { get { return m_RaycastTarget; } set { m_RaycastTarget = value; } }

SetAllDirty

设置layout、material、vertivces需要更新

SetLayoutDirty

layout那节有说,找到根节点的ILayout,加入m_LayoutRebuildQueue

        /// <summary>
        /// Mark the layout as dirty and needing rebuilt.
        /// </summary>
        /// <remarks>
        /// Send a OnDirtyLayoutCallback notification if any elements are registered. See RegisterDirtyLayoutCallback
        /// </remarks>
        public virtual void SetLayoutDirty()
        {
            if (!IsActive())
                return;

            LayoutRebuilder.MarkLayoutForRebuild(rectTransform);

            if (m_OnDirtyLayoutCallback != null)
                m_OnDirtyLayoutCallback();
        }

SetMaterialDirty

加入m_GraphicRebuildQueue队列,同在CanvasUpdateRegistry的PerformUpdate中调用,在layout的rebuild和cull之后调用其rebuild。

private bool InternalRegisterCanvasElementForGraphicRebuild(ICanvasElement element)
{
    if (m_PerformingGraphicUpdate)
    {
        Debug.LogError(string.Format("Trying to add {0} for graphic rebuild while we are already inside a graphic rebuild loop. This is not supported.", element));
        return false;
    }

    return m_GraphicRebuildQueue.AddUnique(element);
}

SetVerticesDirty

加入m_GraphicRebuildQueue队列,调用m_OnDirtyVertsCallback

OnEnable

  1. 调用RegisterGraphicForCanvas进行绑定,将canvas和graphic绑定。在射线检测时使用,获取canvas对应的graphic
  2. 初始化s_WhiteTexture为 Texture2D.whiteTexture;s_WhiteTexture为静态少属性
  3. 调用SetAllDirty(); 所以说SetActive的开销很大,会rebuild all

 /// <summary>
 /// Mark the Graphic and the canvas as having been changed.
 /// </summary>
 protected override void OnEnable()
 {
     base.OnEnable();
     CacheCanvas();
     GraphicRegistry.RegisterGraphicForCanvas(canvas, this);

#if UNITY_EDITOR
     GraphicRebuildTracker.TrackGraphic(this);
#endif
     if (s_WhiteTexture == null)
         s_WhiteTexture = Texture2D.whiteTexture;

     SetAllDirty();
 }

OnCanvasHierarchyChanged

层级改变时,重新RegisterGraphicForCanvas

OnCullingChanged

这可以用来执行之前由于Graphic被删除而被跳过的操作(Rebuild)。

 /// <summary>
 /// This method must be called when <c>CanvasRenderer.cull</c> is modified.
 /// </summary>
 /// <remarks>
 /// This can be used to perform operations that were previously skipped because the <c>Graphic</c> was culled.
 /// </remarks>
 public virtual void OnCullingChanged()
 {
     if (!canvasRenderer.cull && (m_VertsDirty || m_MaterialDirty))
     {
         /// When we were culled, we potentially skipped calls to <c>Rebuild</c>.
         CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this);
     }
 }

OnTransformParentChanged

父节点改变时调用,和OnEnable逻辑差不多

Rebuild

在PreRender模式下,更新Mesh和材质球

/// <summary>
/// Rebuilds the graphic geometry and its material on the PreRender cycle.
/// </summary>
/// <param name="update">The current step of the rendering CanvasUpdate cycle.</param>
/// <remarks>
/// See CanvasUpdateRegistry for more details on the canvas update cycle.
/// </remarks>
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

填充顶点数据,主要调用OnPopulateMesh接口。 同时获取grphic上其他的IMeshModifier组件,调用其ModifyMesh接口修改顶点数据 最后调用canvasRenderer.SetMesh(workerMesh);设置填充的顶点数据

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);
}


[Obsolete("Use OnPopulateMesh(VertexHelper vh) instead.", false)]
/// <summary>
/// Callback function when a UI element needs to generate vertices. Fills the vertex buffer data.
/// </summary>
/// <param name="m">Mesh to populate with UI data.</param>
/// <remarks>
/// Used by Text, UI.Image, and RawImage for example to generate vertices specific to their use case.
/// </remarks>
protected virtual void OnPopulateMesh(Mesh m)
{
    OnPopulateMesh(s_VertexHelper);
    s_VertexHelper.FillMesh(m);
}

/// <summary>
/// Callback function when a UI element needs to generate vertices. Fills the vertex buffer data.
/// </summary>
/// <param name="vh">VertexHelper utility.</param>
/// <remarks>
/// Used by Text, UI.Image, and RawImage for example to generate vertices specific to their use case.
/// </remarks>
protected virtual void OnPopulateMesh(VertexHelper vh)
{
    var r = GetPixelAdjustedRect();
    var v = new Vector4(r.x, r.y, r.x + r.width, r.y + r.height);

    Color32 color32 = color;
    vh.Clear();
    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

更新canvasRenderer的材质球和纹理

/// <summary>
/// Call to update the Material of the graphic onto the CanvasRenderer.
/// </summary>
protected virtual void UpdateMaterial()
{
    if (!IsActive())
        return;

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

Raycast

由GraphicRaycaster 调用

  1. 由当前节点向父节点进行遍历
  2. 遍历节点的所有component
  3. 如果有canvas组件且设置了overrideSorting则不再遍历
  4. 获取ICanvasRaycastFilter组件,调用filter.IsRaycastLocationValid(sp, eventCamera);
  5. 如果返回值为false,返回结果false,否则继续遍历
/// <summary>
/// When a GraphicRaycaster is raycasting into the scene it does two things. First it filters the elements using their RectTransform rect. Then it uses this Raycast function to determine the elements hit by the raycast.
/// </summary>
/// <param name="sp">Screen point being tested</param>
/// <param name="eventCamera">Camera that is being used for the testing.</param>
/// <returns>True if the provided point is a valid location for GraphicRaycaster raycasts.</returns>
public virtual bool Raycast(Vector2 sp, Camera eventCamera)
{
    if (!isActiveAndEnabled)
        return false;

    var t = transform;
    var components = ListPool<Component>.Get();

    bool ignoreParentGroups = false;
    bool continueTraversal = true;

    while (t != null)
    {
        t.GetComponents(components);
        for (var i = 0; i < components.Count; i++)
        {
            var canvas = components[i] as Canvas;
            if (canvas != null && canvas.overrideSorting)
                continueTraversal = false;

            var filter = components[i] as ICanvasRaycastFilter;

            if (filter == null)
                continue;

            var raycastValid = true;

            var group = components[i] as CanvasGroup;
            if (group != null)
            {
                if (ignoreParentGroups == false && group.ignoreParentGroups)
                {
                    ignoreParentGroups = true;
                    raycastValid = filter.IsRaycastLocationValid(sp, eventCamera);
                }
                else if (!ignoreParentGroups)
                    raycastValid = filter.IsRaycastLocationValid(sp, eventCamera);
            }
            else
            {
                raycastValid = filter.IsRaycastLocationValid(sp, eventCamera);
            }

            if (!raycastValid)
            {
                ListPool<Component>.Release(components);
                return false;
            }
        }
        t = continueTraversal ? t.parent : null;
    }
    ListPool<Component>.Release(components);
    return true;
}

IsRaycastLocationValid

Image、Mask、RectMask2D重写了该方法

RectMask2D、Mask

直接调用RectTransformUtility.RectangleContainsScreenPoint(rectTransform, sp, eventCamera);

Image

增加了alpha点击测试,如果alphaHitTestMinimumThreshold在(0,1]之间,会进行判断点击的像素是否大于该值。 x,y是一系列坐标转换得来的activeSprite.texture.GetPixelBilinear(x, y).a >= alphaHitTestMinimumThreshold;

PixelAdjustPoint和GetPixelAdjustedRect

处理canvas.pixelPerfect

强制画布中的元素按像素对齐。仅在 renderMode 为屏幕空间时适用。

启用 pixelPerfect 可使元素看起来更清晰,避免出现模糊。但是,如果许多元素被缩放或旋转过,或者使用了微妙的动画位置或缩放,则禁用 pixelPerfect 可能比较好,这样可使移动更为平滑。

CrossFadeColor

Tweens the CanvasRenderer color associated with this Graphic.变色功能 利用协程,每帧更新已存活时间,除以总时长,得到已存活时间百分比,使用lerp获得当前值

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值