当前位置: 首页 > 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面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:

根据万维钢精英日课6的内容&#xff0c;使用AI&#xff08;2025&#xff09;可以参考以下方法&#xff1a; 四个洞见 模型已经比人聪明&#xff1a;以ChatGPT o3为代表的AI非常强大&#xff0c;能运用高级理论解释道理、引用最新学术论文&#xff0c;生成对顶尖科学家都有用的…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖

在Vuzix M400 AR智能眼镜的助力下&#xff0c;卢森堡罗伯特舒曼医院&#xff08;the Robert Schuman Hospitals, HRS&#xff09;凭借在无菌制剂生产流程中引入增强现实技术&#xff08;AR&#xff09;创新项目&#xff0c;荣获了2024年6月7日由卢森堡医院药剂师协会&#xff0…...

Chrome 浏览器前端与客户端双向通信实战

Chrome 前端&#xff08;即页面 JS / Web UI&#xff09;与客户端&#xff08;C 后端&#xff09;的交互机制&#xff0c;是 Chromium 架构中非常核心的一环。下面我将按常见场景&#xff0c;从通道、流程、技术栈几个角度做一套完整的分析&#xff0c;特别适合你这种在分析和改…...