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 按照对应实现来进行检测。
     

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/178190.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Kafka生产者发送消息的流程

Kafka 生产者发送消息的流程涉及多个步骤&#xff0c;从消息的创建到成功存储在 Kafka 集群中。以下是 Kafka 生产者发送消息的主要步骤&#xff1a; 1. 创建消息 生产者首先创建一个消息&#xff0c;消息通常包含一个键&#xff08;可选&#xff09;和一个值&#xff0c;以及…

Verilog基础:时序调度中的竞争(二)

相关阅读 Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482 作为一个硬件描述语言&#xff0c;Verilog HDL常常需要使用语句描述并行执行的电路&#xff0c;但其实在仿真器的底层&#xff0c;这些并行执行的语句是有先后顺序…

Ubuntu:安装VSCode

参考博客Ubuntu下安装VSCODE_ubuntu安装vscode-CSDN博客中的第二种方式【安装包方式安装】&#xff0c;即可&#xff0c;安装非常easy~~~ 安装包方式安装&#xff1a; 1. 从VSCode官网下载最新版的deb安装包&#xff1a; https://code.visualstudio.com/Download&#xff0c;…

使用Prometheus监控Synology(群辉)

1、简介 在现代的IT环境中&#xff0c;对于服务器和网络设备的监控是至关重要的。Synology&#xff08;群辉&#xff09;作为一种流行的网络存储解决方案&#xff0c;为用户提供了高性能和可靠的存储服务。然而&#xff0c;了解Synology设备的运行状况和性能指标对于确保其正常…

车辆管控大数据可视化平台案例源码分析【可视化项目案例-10】

🎉🎊🎉 你的技术旅程将在这里启航! 🚀🚀 本专栏包括但不限于大屏可视化、图表可视化等等。订阅专栏用户在文章底部可下载对应案例源码以供大家深入的学习研究。 🎓 每一个案例都会提供完整代码和详细的讲解,不论你是初学者还是资深开发者,这里都有适合你的内容。…

Windows平台下的oracle 11G-11.2.0.4补丁升级操作指南

序号 文件名称 文件说明 1 p6880880_112000_MSWIN-x86-64_OPatch 11.2.0.3.33 for DB 11.2.0.0.0 (Feb 2022) 用于升级 OPatch 2 DB_PSU_11.2.0.4.220118 (Jan 2022)_p33488457_112040_MSWIN-x86-64 主要补丁文件 注意&#xff1a;请用管理员权限运行文件内命令&#…

Stable Video Diffusion(SVD)安装和测试

Stable Video Diffusion&#xff08;SVD&#xff09;安装和测试 官网 github | https://github.com/Stability-AI/generative-modelsHugging Face | https://huggingface.co/stabilityai/stable-video-diffusion-img2vid-xtPaper | https://stability.ai/research/stable-vid…

Nodejs+Vue校园餐厅外卖订餐点餐系统 PHP高校食堂 微信小程序_0u4hl 多商家

对于校园订餐小程序将是又一个传统管理到智能化信息管理的改革&#xff0c;对于传统的校园订餐管理&#xff0c;所包括的信息内容比较多&#xff0c;对于用户想要对这些数据进行管理维护需要花费很大的时间信息&#xff0c;而且对于数据的存储比较麻烦&#xff0c;想要查找某一…

软工2021上下午第六题(组合模式)

阅读下列说明和Java代码&#xff0c;将应填入&#xff08;n&#xff09;处的字句写在答题纸的对应栏内。 【说明】 层叠菜单是窗口风格的软件系统中经常采用的一种系统功能组织方式。层叠菜单中包含的可能是一个菜单项&#xff08;直接对应某个功能&#xff09;&#xff0c;也可…

中文编程开发工具高级版全部构件工具箱列表,中文编程自由版下载

中文编程开发工具高级版全部构件工具箱列表&#xff0c;中文编程自由版下载 附&#xff1a;中文编程工具构件工具箱总共22组305个构件&#xff0c;构件明细如下&#xff1a;文本件16个&#xff1a; &#xff08;普通标签&#xff0c;连接标签&#xff0c;闪动标签&#xff0c;立…

香港高才通计划官网入口,附申请流程+高校名单+好处!

香港高才通计划官网入口&#xff0c;附申请流程高校名单好处&#xff01; 首先给出官网入口&#xff1a; 或者百度“香港入境处”&#xff0c;点击带有官方标志的入境处网站&#xff1a; 然后进入“我们的服务”→“签证/许可”选项→点“吸引人才”→“高端人才通行證計劃”即…

HelpLook可以作为wordpress的替代品,帮助企业快速搭建博客

博客作为一个非常有价值的平台&#xff0c;在当今的数字时代具有重要的意义。对于个人和企业来说&#xff0c;选择一款适合自己需求的专业博客搭建软件至关重要。本篇文章将会通过对比两个专业的博客搭建软件——HelpLook和WordPress&#xff0c;看看为什么我说HelpLook可以作为…

内部类, Comparable接口, Comparator接口, Cloneable接口 ---java

目录 一. 内部类 1.1 静态内部类 1.2 实例内部类 1.3匿名内部类 二. 接口的使用实例 2.1 Comparable接口 2.2 Comparator接口 ---比较器 2.3 Cloneable接口 深拷贝浅拷贝 一. 内部类 当一个事物的内部&#xff0c;还有一个部分需要一个完整的结构进行描述&#xff0…

Unity中Shader的BRDF解析(一)

文章目录 前言现在我们主要来看Standard的 漫反射 和 镜面反射一、PBS的核心计算BRDF二、Standard的镜面高光颜色三、具体的BRDF计算对于BRDF的具体计算&#xff0c;在下篇文章中&#xff0c;继续解析 四、最终代码.cginc文件Shader文件 前言 在上篇文章中&#xff0c;我们解析…

DDR-MIG 学习记录

MIG调试总结&#xff1a; 对vivado软件中用于控制DDR2 / DDR3 的 控制器MIG(Memory Interface Generator)IP核进行了仿真测试&#xff0c;以学习如何用IP核来控制FPGA板载SDRAM的读写。我们只需要学会MIG的接口控制就可以。 ①配置IP核 Xilinx 的 DDR 控制器的名称简写为 MIG&…

brk和sbrk

在计算机程序中&#xff0c;“program break”通常指的是堆的当前内存边界。当我们改变堆的大小&#xff08;即分配或释放内存&#xff09;&#xff0c;其实就是在命令内核改变进程的“program break”位置。 最初&#xff0c;“program break”正好位于未初始化数据段(bss)末…

vue3中的动态component组件

is属性来指定要渲染的组件(填写组件名&#xff09; 多个子组件通过component标签挂载在同一个父组件中&#xff0c; 可以修改is属性进行动态切换组件。 可以搭配<keep-alive></keep-alive>使用。 父组件代码&#xff1a; <template><div style"fon…

2017年五一杯数学建模A题公交车排班问题解题全过程文档及程序

2017年五一杯数学建模 A题 公交车排班问题 原题再现 随着徐州市经济的快速发展&#xff0c;公交车系统对于人们的出行扮演着越来越重要的角色。在公交车资源有限的情况下&#xff0c;合理的编排公交车的行车计划成为公交公司亟待解决的问题。以下给出公交车排班问题中的部分名…

【NI-RIO入门】为CompactRIO供电

在大多数情况下&#xff0c;您可以使用可直接连接系统的电源&#xff0c;例如墙上的电源插座。但是&#xff0c;某些应用程序或环境缺乏可用电源&#xff0c;您必须使用其他电源&#xff0c;例如电池。无论您是否有可用电源&#xff0c;您可能都希望通过为系统提供一些冗余来确…

洛谷 P1605 USACO迷宫 (详细解析和AC代码)【深搜+打表】

P1605 迷宫 前言题目题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示题目分析注意事项 代码后话王婆卖瓜 题目来源 前言 没什么好说的深搜yyds&#xff01;直接深搜一遍过&#xff01; 题目 题目描述 给定一个 N M N \times M NM 方格的迷宫&#xff0c;迷…