当前位置: 首页 > 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.父子同名属性是否…...

JavaSec-RCE

简介 RCE(Remote Code Execution)&#xff0c;可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景&#xff1a;Groovy代码注入 Groovy是一种基于JVM的动态语言&#xff0c;语法简洁&#xff0c;支持闭包、动态类型和Java互操作性&#xff0c…...

vscode里如何用git

打开vs终端执行如下&#xff1a; 1 初始化 Git 仓库&#xff08;如果尚未初始化&#xff09; git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

【git】把本地更改提交远程新分支feature_g

创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

初探Service服务发现机制

1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能&#xff1a;服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源&#xf…...

Git 3天2K星标:Datawhale 的 Happy-LLM 项目介绍(附教程)

引言 在人工智能飞速发展的今天&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;已成为技术领域的焦点。从智能写作到代码生成&#xff0c;LLM 的应用场景不断扩展&#xff0c;深刻改变了我们的工作和生活方式。然而&#xff0c;理解这些模型的内部…...

为什么要创建 Vue 实例

核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...