当前位置: 首页 > news >正文

Unity - Graphic解析

Gpahic 的作用

Graphic 是 Unity最基础的图形基类。主要负责UGUI的显示部分。

        

由上图可以看你出我们经常使用的Image,Text,都是继承自Graphic。

Graphic的渲染流程

在Graphic的源码中有以下属性

 [NonSerialized] private CanvasRenderer m_CanvasRenderer;
Graphic会收集渲染所需要的数据如:顶点,材质,等信息。然后对 CanvasRenderer设置 材质(Material)、贴图(Texture)、网格 让其进行渲染到屏幕中。

以下是Graphic的源码:

using System;
#if UNITY_EDITOR
using System.Reflection;
#endif
using System.Collections.Generic;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.Serialization;
using UnityEngine.UI.CoroutineTween;namespace UnityEngine.UI
{/// <summary>/// Base class for all UI components that should be derived from when creating new Graphic types./// </summary>[DisallowMultipleComponent][RequireComponent(typeof(RectTransform))][ExecuteAlways]public abstract class Graphic: UIBehaviour,ICanvasElement{static protected Material s_DefaultUI = null;static protected Texture2D s_WhiteTexture = null;/// <summary>/// Default material used to draw UI elements if no explicit material was specified./// </summary>static public Material defaultGraphicMaterial{get{if (s_DefaultUI == null)s_DefaultUI = Canvas.GetDefaultCanvasMaterial();return s_DefaultUI;}}// Cached and saved values[FormerlySerializedAs("m_Mat")][SerializeField] protected Material m_Material;[SerializeField] private Color m_Color = Color.white;[NonSerialized] protected bool m_SkipLayoutUpdate;[NonSerialized] protected bool m_SkipMaterialUpdate;/// <summary>/// Base color of the Graphic./// </summary>/// <remarks>public virtual Color color { get { return m_Color; } set { if (SetPropertyUtility.SetColor(ref m_Color, value)) SetVerticesDirty(); } }[SerializeField] 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{if (value != m_RaycastTarget){if (m_RaycastTarget)GraphicRegistry.UnregisterRaycastGraphicForCanvas(canvas, this);m_RaycastTarget = value;if (m_RaycastTarget && isActiveAndEnabled)GraphicRegistry.RegisterRaycastGraphicForCanvas(canvas, this);}}}[SerializeField]private Vector4 m_RaycastPadding = new Vector4();/// <summary>/// Padding to be applied to the masking/// X = Left/// Y = Bottom/// Z = Right/// W = Top/// </summary>public Vector4 raycastPadding{get { return m_RaycastPadding; }set{m_RaycastPadding = value;}}[NonSerialized] private RectTransform m_RectTransform;[NonSerialized] private CanvasRenderer m_CanvasRenderer;[NonSerialized] private Canvas m_Canvas;[NonSerialized] private bool m_VertsDirty;[NonSerialized] private bool m_MaterialDirty;[NonSerialized] protected UnityAction m_OnDirtyLayoutCallback;[NonSerialized] protected UnityAction m_OnDirtyVertsCallback;[NonSerialized] protected UnityAction m_OnDirtyMaterialCallback;[NonSerialized] protected static Mesh s_Mesh;[NonSerialized] private static readonly VertexHelper s_VertexHelper = new VertexHelper();[NonSerialized] protected Mesh m_CachedMesh;[NonSerialized] protected Vector2[] m_CachedUvs;// Tween controls for the Graphic[NonSerialized]private readonly TweenRunner<ColorTween> m_ColorTweenRunner;protected bool useLegacyMeshGeneration { get; set; }// Called by Unity prior to deserialization,// should not be called by usersprotected Graphic(){if (m_ColorTweenRunner == null)m_ColorTweenRunner = new TweenRunner<ColorTween>();m_ColorTweenRunner.Init(this);useLegacyMeshGeneration = true;}/// <summary>/// Set all properties of the Graphic dirty and needing rebuilt./// Dirties Layout, Vertices, and Materials./// </summary>public virtual void SetAllDirty(){// Optimization: Graphic layout doesn't need recalculation if// the underlying Sprite is the same size with the same texture.// (e.g. Sprite sheet texture animation)if (m_SkipLayoutUpdate){m_SkipLayoutUpdate = false;}else{SetLayoutDirty();}if (m_SkipMaterialUpdate){m_SkipMaterialUpdate = false;}else{SetMaterialDirty();}SetVerticesDirty();}/// <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();}/// <summary>/// Mark the vertices as dirty and needing rebuilt./// </summary>/// <remarks>/// Send a OnDirtyVertsCallback notification if any elements are registered. See RegisterDirtyVerticesCallback/// </remarks>public virtual void SetVerticesDirty(){if (!IsActive())return;m_VertsDirty = true;CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this);if (m_OnDirtyVertsCallback != null)m_OnDirtyVertsCallback();}/// <summary>/// Mark the material as dirty and needing rebuilt./// </summary>/// <remarks>/// Send a OnDirtyMaterialCallback notification if any elements are registered. See RegisterDirtyMaterialCallback/// </remarks>public virtual void SetMaterialDirty(){if (!IsActive())return;m_MaterialDirty = true;CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this);if (m_OnDirtyMaterialCallback != null)m_OnDirtyMaterialCallback();}protected override void OnRectTransformDimensionsChange(){if (gameObject.activeInHierarchy){// prevent double dirtying...if (CanvasUpdateRegistry.IsRebuildingLayout())SetVerticesDirty();else{SetVerticesDirty();SetLayoutDirty();}}}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();}/// <summary>/// Absolute depth of the graphic, used by rendering and events -- lowest to highest./// </summary>/// <example>/// The depth is relative to the first root canvas.////// Canvas///  Graphic - 1///  Graphic - 2///  Nested Canvas///     Graphic - 3///     Graphic - 4///  Graphic - 5////// This value is used to determine draw and event ordering./// </example>public int depth { get { return canvasRenderer.absoluteDepth; } }/// <summary>/// The RectTransform component used by the Graphic. Cached for speed./// </summary>public RectTransform rectTransform{get{// The RectTransform is a required component that must not be destroyed. Based on this assumption, a// null-reference check is sufficient.if (ReferenceEquals(m_RectTransform, null)){m_RectTransform = GetComponent<RectTransform>();}return m_RectTransform;}}/// <summary>/// A reference to the Canvas this Graphic is rendering to./// </summary>/// <remarks>/// In the situation where the Graphic is used in a hierarchy with multiple Canvases, the Canvas closest to the root will be used./// </remarks>public Canvas canvas{get{if (m_Canvas == null)CacheCanvas();return m_Canvas;}}private void CacheCanvas(){var list = ListPool<Canvas>.Get();gameObject.GetComponentsInParent(false, list);if (list.Count > 0){// Find the first active and enabled canvas.for (int i = 0; i < list.Count; ++i){if (list[i].isActiveAndEnabled){m_Canvas = list[i];break;}// if we reached the end and couldn't find an active and enabled canvas, we should return null . case 1171433if (i == list.Count - 1)m_Canvas = null;}}else{m_Canvas = null;}ListPool<Canvas>.Release(list);}/// <summary>/// A reference to the CanvasRenderer populated by this Graphic./// </summary>public CanvasRenderer canvasRenderer{get{// The CanvasRenderer is a required component that must not be destroyed. Based on this assumption, a// null-reference check is sufficient.if (ReferenceEquals(m_CanvasRenderer, null)){m_CanvasRenderer = GetComponent<CanvasRenderer>();if (ReferenceEquals(m_CanvasRenderer, null)){m_CanvasRenderer = gameObject.AddComponent<CanvasRenderer>();}}return m_CanvasRenderer;}}/// <summary>/// Returns the default material for the graphic./// </summary>public virtual Material defaultMaterial{get { return defaultGraphicMaterial; }}/// <summary>/// The Material set by the user/// </summary>public virtual Material material{get{return (m_Material != null) ? m_Material : defaultMaterial;}set{if (m_Material == value)return;m_Material = value;SetMaterialDirty();}}/// <summary>/// The material that will be sent for Rendering (Read only)./// </summary>/// <remarks>/// This is the material that actually gets sent to the CanvasRenderer. By default it's the same as [[Graphic.material]]. When extending Graphic you can override this to send a different material to the CanvasRenderer than the one set by Graphic.material. This is useful if you want to modify the user set material in a non destructive manner./// </remarks>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);ListPool<Component>.Release(components);return currentMat;}}/// <summary>/// The graphic's texture. (Read Only)./// </summary>/// <remarks>/// This is the Texture that gets passed to the CanvasRenderer, Material and then Shader _MainTex.////// When implementing your own Graphic you can override this to control which texture goes through the UI Rendering pipeline.////// Bear in mind that Unity tries to batch UI elements together to improve performance, so its ideal to work with atlas to reduce the number of draw calls./// </remarks>public virtual Texture mainTexture{get{return s_WhiteTexture;}}/// <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_EDITORGraphicRebuildTracker.TrackGraphic(this);
#endifif (s_WhiteTexture == null)s_WhiteTexture = Texture2D.whiteTexture;SetAllDirty();}/// <summary>/// Clear references./// </summary>protected override void OnDisable(){
#if UNITY_EDITORGraphicRebuildTracker.UnTrackGraphic(this);
#endifGraphicRegistry.UnregisterGraphicForCanvas(canvas, this);CanvasUpdateRegistry.UnRegisterCanvasElementForRebuild(this);if (canvasRenderer != null)canvasRenderer.Clear();LayoutRebuilder.MarkLayoutForRebuild(rectTransform);base.OnDisable();}protected override void OnDestroy(){if (m_CachedMesh)Destroy(m_CachedMesh);m_CachedMesh = null;base.OnDestroy();}protected override void OnCanvasHierarchyChanged(){// Use m_Cavas so we dont auto call CacheCanvasCanvas 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);}}/// <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);}}/// <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;}}public virtual void LayoutComplete(){}public virtual void GraphicUpdateComplete(){}/// <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);}/// <summary>/// Call to update the geometry of the Graphic onto the CanvasRenderer./// </summary>protected virtual void UpdateGeometry(){if (useLegacyMeshGeneration){DoLegacyMeshGeneration();}else{DoMeshGeneration();}}private void DoMeshGeneration(){if (rectTransform != null && rectTransform.rect.width >= 0 && rectTransform.rect.height >= 0)OnPopulateMesh(s_VertexHelper);elses_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);}private void DoLegacyMeshGeneration(){if (rectTransform != null && rectTransform.rect.width >= 0 && rectTransform.rect.height >= 0){
#pragma warning disable 618OnPopulateMesh(workerMesh);
#pragma warning restore 618}else{workerMesh.Clear();}var components = ListPool<Component>.Get();GetComponents(typeof(IMeshModifier), components);for (var i = 0; i < components.Count; i++){
#pragma warning disable 618((IMeshModifier)components[i]).ModifyMesh(workerMesh);
#pragma warning restore 618}ListPool<Component>.Release(components);canvasRenderer.SetMesh(workerMesh);}protected static Mesh workerMesh{get{if (s_Mesh == null){s_Mesh = new Mesh();s_Mesh.name = "Shared UI Mesh";s_Mesh.hideFlags = HideFlags.HideAndDontSave;}return s_Mesh;}}[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)][Obsolete("Use OnPopulateMesh instead.", true)]protected virtual void OnFillVBO(System.Collections.Generic.List<UIVertex> vbo) {}[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);}#if UNITY_EDITOR/// <summary>/// Editor-only callback that is issued by Unity if a rebuild of the Graphic is required./// Currently sent when an asset is reimported./// </summary>public virtual void OnRebuildRequested(){// when rebuild is requested we need to rebuild all the graphics /// and associated components... The correct way to do this is by// calling OnValidate... Because MB's don't have a common base class// we do this via reflection. It's nasty and ugly... Editor only.m_SkipLayoutUpdate = true;var mbs = gameObject.GetComponents<MonoBehaviour>();foreach (var mb in mbs){if (mb == null)continue;var methodInfo = mb.GetType().GetMethod("OnValidate", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);if (methodInfo != null)methodInfo.Invoke(mb, null);}m_SkipLayoutUpdate = false;}protected override void Reset(){SetAllDirty();}#endif// Call from unity if animation properties have changedprotected override void OnDidApplyAnimationProperties(){SetAllDirty();}/// <summary>/// Make the Graphic have the native size of its content./// </summary>public virtual void SetNativeSize() {}/// <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;}#if UNITY_EDITORprotected override void OnValidate(){base.OnValidate();SetAllDirty();}#endif///<summary>///Adjusts the given pixel to be pixel perfect.///</summary>///<param name="point">Local space point.</param>///<returns>Pixel perfect adjusted point.</returns>///<remarks>///Note: This is only accurate if the Graphic root Canvas is in Screen Space.///</remarks>public Vector2 PixelAdjustPoint(Vector2 point){if (!canvas || canvas.renderMode == RenderMode.WorldSpace || canvas.scaleFactor == 0.0f || !canvas.pixelPerfect)return point;else{return RectTransformUtility.PixelAdjustPoint(point, transform, canvas);}}/// <summary>/// Returns a pixel perfect Rect closest to the Graphic RectTransform./// </summary>/// <remarks>/// Note: This is only accurate if the Graphic root Canvas is in Screen Space./// </remarks>/// <returns>A Pixel perfect Rect.</returns>public Rect GetPixelAdjustedRect(){if (!canvas || canvas.renderMode == RenderMode.WorldSpace || canvas.scaleFactor == 0.0f || !canvas.pixelPerfect)return rectTransform.rect;elsereturn RectTransformUtility.PixelAdjustRect(rectTransform, canvas);}///<summary>///Tweens the CanvasRenderer color associated with this Graphic.///</summary>///<param name="targetColor">Target color.</param>///<param name="duration">Tween duration.</param>///<param name="ignoreTimeScale">Should ignore Time.scale?</param>///<param name="useAlpha">Should also Tween the alpha channel?</param>public virtual void CrossFadeColor(Color targetColor, float duration, bool ignoreTimeScale, bool useAlpha){CrossFadeColor(targetColor, duration, ignoreTimeScale, useAlpha, true);}///<summary>///Tweens the CanvasRenderer color associated with this Graphic.///</summary>///<param name="targetColor">Target color.</param>///<param name="duration">Tween duration.</param>///<param name="ignoreTimeScale">Should ignore Time.scale?</param>///<param name="useAlpha">Should also Tween the alpha channel?</param>/// <param name="useRGB">Should the color or the alpha be used to tween</param>public virtual void CrossFadeColor(Color targetColor, float duration, bool ignoreTimeScale, bool useAlpha, bool useRGB){if (canvasRenderer == null || (!useRGB && !useAlpha))return;Color currentColor = canvasRenderer.GetColor();if (currentColor.Equals(targetColor)){m_ColorTweenRunner.StopTween();return;}ColorTween.ColorTweenMode mode = (useRGB && useAlpha ?ColorTween.ColorTweenMode.All :(useRGB ? ColorTween.ColorTweenMode.RGB : ColorTween.ColorTweenMode.Alpha));var colorTween = new ColorTween {duration = duration, startColor = canvasRenderer.GetColor(), targetColor = targetColor};colorTween.AddOnChangedCallback(canvasRenderer.SetColor);colorTween.ignoreTimeScale = ignoreTimeScale;colorTween.tweenMode = mode;m_ColorTweenRunner.StartTween(colorTween);}static private Color CreateColorFromAlpha(float alpha){var alphaColor = Color.black;alphaColor.a = alpha;return alphaColor;}///<summary>///Tweens the alpha of the CanvasRenderer color associated with this Graphic.///</summary>///<param name="alpha">Target alpha.</param>///<param name="duration">Duration of the tween in seconds.</param>///<param name="ignoreTimeScale">Should ignore [[Time.scale]]?</param>public virtual void CrossFadeAlpha(float alpha, float duration, bool ignoreTimeScale){CrossFadeColor(CreateColorFromAlpha(alpha), duration, ignoreTimeScale, true, false);}/// <summary>/// Add a listener to receive notification when the graphics layout is dirtied./// </summary>/// <param name="action">The method to call when invoked.</param>public void RegisterDirtyLayoutCallback(UnityAction action){m_OnDirtyLayoutCallback += action;}/// <summary>/// Remove a listener from receiving notifications when the graphics layout are dirtied/// </summary>/// <param name="action">The method to call when invoked.</param>public void UnregisterDirtyLayoutCallback(UnityAction action){m_OnDirtyLayoutCallback -= action;}/// <summary>/// Add a listener to receive notification when the graphics vertices are dirtied./// </summary>/// <param name="action">The method to call when invoked.</param>public void RegisterDirtyVerticesCallback(UnityAction action){m_OnDirtyVertsCallback += action;}/// <summary>/// Remove a listener from receiving notifications when the graphics vertices are dirtied/// </summary>/// <param name="action">The method to call when invoked.</param>public void UnregisterDirtyVerticesCallback(UnityAction action){m_OnDirtyVertsCallback -= action;}/// <summary>/// Add a listener to receive notification when the graphics material is dirtied./// </summary>/// <param name="action">The method to call when invoked.</param>public void RegisterDirtyMaterialCallback(UnityAction action){m_OnDirtyMaterialCallback += action;}/// <summary>/// Remove a listener from receiving notifications when the graphics material are dirtied/// </summary>/// <param name="action">The method to call when invoked.</param>public void UnregisterDirtyMaterialCallback(UnityAction action){m_OnDirtyMaterialCallback -= action;}}
}
1.SetAllDirty、SetLayoutDirty

  Graphic使用了脏标记模式(游戏编程模式里面有这个设计模式),每当一些属性发生改变后不会立即更新属性,而是将这些变化的属性打上标记,然后CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild 方法会向一个队列中添加一个元素,并在某一个时刻 (在 OnEnable、Reset、OnDidApplyAnimationProperties、OnValidate、OnTransformParentChanged等等事件中,需要更新表现时都会调用SetAllDirty,发送对应的事件。给 CanvasUpdateRegistry 标记需要被Rebuild) 一起更新。

2.Rebuild

执行 Rebuild 函数。 这时候会根据Dirty的标识(SetAllDirty里面将标识设置为true,这里设置为false)来调用 UpdateGeometry、UpdateMaterial。

3.更新材质 UpdateMaterial. (直接给CanvasRenderer设置值)
4.更新顶点数据 UpdateGeometry。
  • 根据代码我们可以看到首先调用 OnPopulateMesh 来生成Mesh数据。 Image、RawImage以及Text都对这个函数进行重写来生成特定的顶点数据。
  • 获取当前GameObject上的所有实现了 IMeshModifier 接口的组件并调用 ModifyMesh 方法来修改Mesh数据
  • 给 CanvasRenderer 设置更新后的数据

Graphic的事件: GraphicRegistry  

GraphicRegistry是负责让Canvas知道 Graphic 是否被操作了,是否需要渲染内容了,从上面源码中可以看到 OnEnable、OnCanvasHierarchyChanged、OnTransformParentChanged

中注册了自己

GraphicRegistry.RegisterGraphicForCanvas(canvas, this);

在 OnDisable中取消注册

GraphicRegistry.UnregisterGraphicForCanvas(currentCanvas, this);

通过 Graphic 给 GraphicRegistry 注册完成后,在 GraphicRaycaster 中的 Raycast函数中会进行获取的操作。

  1. GraphicRaycaster 获取 GraphicRegistry 中所注册的 Graphic 并调用 Graphic 中的 Raycast 方法。
  2. 获取Graphic所挂载的transform上的所有Components检测是否实现了ICanvasRaycastFilter, 对所有实现了 ICanvasRaycastFilter 接口的调用 IsRaycastLocationValid
  3. IsRaycastLocationValid 按照对应实现来进行检测。
     

相关文章:

Unity - Graphic解析

Gpahic 的作用 Graphic 是 Unity最基础的图形基类。主要负责UGUI的显示部分。 由上图可以看你出我们经常使用的Image&#xff0c;Text&#xff0c;都是继承自Graphic。 Graphic的渲染流程 在Graphic的源码中有以下属性 [NonSerialized] private CanvasRenderer m_CanvasRend…...

哈希思想的应用

目录 1.位图 位图的实现 题目变形一 题目变形二 题目变形三 总结&#xff1a; 2.布隆过滤器 概念 布隆过滤器的实现 3.哈希切割的思想 1.位图 哈希表和位图是数据结构中常用的两种技术。哈希表是一种数据结构&#xff0c;通过哈希函数把数据和位置进行映射&#xff0c…...

React入门使用 (官方文档向 Part1)

文章目录 React组件:万物皆组件 JSX: 将标签引入 JavaScriptJSX 规则1. 只能返回一个根元素2. 标签必须闭合3. 使用驼峰式命名法给 ~~所有~~ 大部分属性命名&#xff01;高级提示&#xff1a;使用 JSX 转化器 在 JSX 中通过大括号使用 JavaScript使用引号传递字符串使用大括号&…...

87基于matlab的双卡尔曼滤波算法

基于matlab的双卡尔曼滤波算法。第一步使用了卡尔曼滤波算法&#xff0c;用电池电压来修正SOC&#xff0c;然后将修正后的SOC作为第二个卡尔曼滤波算法的输入&#xff0c;对安时积分法得到的SOC进行修正&#xff0c;最终得到双卡尔曼滤波算法SOC估计值。结合EKF算法和安时积分法…...

Jacobi迭代与SOR迭代求解希尔伯特矩阵

给出线性方程组 Hn*x b&#xff0c;其中系数矩阵Hn为希尔伯特矩阵&#xff1a; 假设 x ∗ (1, 1, . . . , 1)T&#xff0c;b Hnx ∗。若取 n 6,8, 10&#xff0c;分别用 Jacobi 迭代法及 SOR迭代&#xff08;ω 1, 1:25,1:5&#xff09;求解&#xff0c;比较计算结果。…...

【云备份】配置加载文件模块

文章目录 配置信息设计配置文件加载cloud.conf配置文件单例模式的使用ReadConfigFile —— 读取配置文件GetInstance —— 创建对象其他函数的实现 具体实现cloud.confconfig.hpp 配置信息设计 使用文件配置加载一些程序运行的关键信息 可以让程序的运行更加灵活 配置信息&am…...

sqlserver写入中文乱码问题

sqlserver写入中文乱码问题解决方案 首先查看sqlserver数据库编码 首先查看sqlserver数据库编码 查询语句&#xff1a;SELECT COLLATIONPROPERTY(Chinese_PRC_Stroke_CI_AI_KS_WS, CodePage)&#xff1b; 对应的编码&#xff1a; 936 简体中文GBK 950 繁体中文BIG5 437 美国/加…...

【亚马逊云】基于EC2以 All-in-One 模式快速部署 KubeSphere 和 Kubernetes

文章目录 1. 云实例配置说明2. SSH连接云实例3. 查看系统版本4. 修改主机名5. 安装依赖项6. 安全组和DNS修改7. 下载KubeKey8. 同时安装Kubesphere和Kubernetes[可选]单独安装Kubernetes[可选]单独安装KubeSphere9. 验证KubeSphere安装结果10. 登录KubeSphere控制台[可选]安装K…...

使用 ChatGPT 创建 Makefile 构建系统:从 Docker 开始

使用 Docker 搭配 ChatGPT 创建 Makefile 构建系统 Makefile 构建系统是嵌入式软件团队实现其开发流程现代化的基础。构建系统不仅允许开发人员选择各种构建目标&#xff0c;还可以将这些构建集成到持续集成/持续部署 (CI/CD) 流程中。使用诸如 ChatGPT 这样的人工智能 (AI) 工…...

嵌入式设备摄像头基础知识

工作原理 摄像头的工作原理是&#xff0c;当光线通过镜头聚焦到图像传感器上时&#xff0c;传感器会将光信号转换为电信号&#xff0c;并将其传输给处理器进行处理。处理器通过算法对图像信号进行增强、去噪、压缩等操作&#xff0c;并将其转换为数字信号输出给计算机或其他设…...

使用Pytorch从零开始构建Normalizing Flow

归一化流 (Normalizing Flow) &#xff08;Rezende & Mohamed&#xff0c;2015&#xff09;学习可逆映射 f : X → Z f: X \rightarrow Z f:X→Z, 在这里X是我们的数据分布&#xff0c;Z是选定的潜在分布。 归一化流是生成模型家族的一部分&#xff0c;其中包括变分自动编…...

一个tomcat中部署的多个war,相当于几个jvm

请直接去看原文 原文链接:一个tomcat有几个jvm-CSDN博客 --------------------------------------------------------------------------------------------------------------------------------- 前几天向unmi提问&#xff0c;今天他答复了。我觉得答复很清楚&#xff0c;…...

2023年第十六届中国系统架构师大会(SACC2023)-核心PPT资料下载

一、峰会简介 本届大会以“数字转型 架构演进”为主题&#xff0c; 涵盖多个热门领域&#xff0c;如多云多活、海量分布式存储、容器、云成本、AIGC大数据等&#xff0c;同时还关注系统架构在各个行业中的应用&#xff0c;如金融、制造业、互联网、教育等。 与往届相比&#…...

高校大学校园后勤移动报修系统 微信小程序uniapp+vue

本文主要是针对线下校园后勤移动报修传统管理方式中管理不便与效率低的缺点&#xff0c;将电子商务和计算机技术结合起来&#xff0c;开发出管理便捷&#xff0c;效率高的基于app的大学校园后勤移动报修app。该系统、操作简单、界面友好、易于管理和维护&#xff1b;而且对后勤…...

docker常见问题汇总

docker常见问题 ❓问题1&#xff1a;启动docker容器时&#xff0c;报错Unknown runtime specified nvidia. 当我启动一个容器时&#xff0c;运行以下命令&#xff1a; docker run --runtimenvidia 。。。。 后面一部分命令没写出来&#xff0c;此时报错的信息如下&#xff1a;…...

JMeter 测试脚本编写技巧

JMeter 是一款开源软件&#xff0c;用于进行负载测试、性能测试及功能测试。测试人员可以使用 JMeter 编写测试脚本&#xff0c;模拟多种不同的负载情况&#xff0c;从而评估系统的性能和稳定性。以下是编写 JMeter 测试脚本的步骤。 第 1 步&#xff1a;创建测试计划 在JMet…...

力扣6:N字形变化

代码&#xff1a; class Solution { public:string convert(string s, int numRows){int lens.size();if(numRows1){return s;}int d2*numRows-2;int count0;string ret;//第一行&#xff01;for(int i0;i<len;id){rets[i];}//第k行&#xff01;for(int i1;i<numRows-1;…...

【上海大学数字逻辑实验报告】一、基本门电路

一、 实验目的 熟悉TTL中、小规模集成电路的外形、管脚和使用方法&#xff1b;了解和掌握基本逻辑门电路的输入与输出之间的逻辑关系及使用规则。 二、 实验原理 实现基本逻辑运算和常用逻辑运算的单元电路称为逻辑门电路。门电路通常用高电平VH表示逻辑值“1”&#xff0c;…...

基于xml配置的AOP

目录 xml方式AOP快速入门 xml方式AOP配置详解 xml方式AOP快速入门 xml方式配置AOP的步骤 导入AOP相关坐标 <dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.13</version></de…...

java学习part12多态

99-面向对象(进阶)-面向对象的特征三&#xff1a;多态性_哔哩哔哩_bilibili 1.多态&#xff08;仅限方法&#xff09; 父类引用指向子类对象。 调用重写的方法&#xff0c;就会执行子类重写的方法。 编译看引用表面类型&#xff0c;执行看实际变量类型。 2.父子同名属性是否…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候&#xff0c;遇到了一些问题&#xff0c;记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

STM32+rt-thread判断是否联网

一、根据NETDEV_FLAG_INTERNET_UP位判断 static bool is_conncected(void) {struct netdev *dev RT_NULL;dev netdev_get_first_by_flags(NETDEV_FLAG_INTERNET_UP);if (dev RT_NULL){printf("wait netdev internet up...");return false;}else{printf("loc…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

sqlserver 根据指定字符 解析拼接字符串

DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案&#xff0c;允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

嵌入式学习笔记DAY33(网络编程——TCP)

一、网络架构 C/S &#xff08;client/server 客户端/服务器&#xff09;&#xff1a;由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序&#xff0c;负责提供用户界面和交互逻辑 &#xff0c;接收用户输入&#xff0c;向服务器发送请求&#xff0c;并展示服务…...

Golang——9、反射和文件操作

反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一&#xff1a;使用Read()读取文件2.3、方式二&#xff1a;bufio读取文件2.4、方式三&#xff1a;os.ReadFile读取2.5、写…...

关于uniapp展示PDF的解决方案

在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项&#xff1a; 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库&#xff1a; npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...