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函数中会进行获取的操作。
- GraphicRaycaster 获取 GraphicRegistry 中所注册的 Graphic 并调用 Graphic 中的 Raycast 方法。
- 获取Graphic所挂载的transform上的所有Components检测是否实现了ICanvasRaycastFilter, 对所有实现了 ICanvasRaycastFilter 接口的调用 IsRaycastLocationValid
- IsRaycastLocationValid 按照对应实现来进行检测。
相关文章:
Unity - Graphic解析
Gpahic 的作用 Graphic 是 Unity最基础的图形基类。主要负责UGUI的显示部分。 由上图可以看你出我们经常使用的Image,Text,都是继承自Graphic。 Graphic的渲染流程 在Graphic的源码中有以下属性 [NonSerialized] private CanvasRenderer m_CanvasRend…...
哈希思想的应用
目录 1.位图 位图的实现 题目变形一 题目变形二 题目变形三 总结: 2.布隆过滤器 概念 布隆过滤器的实现 3.哈希切割的思想 1.位图 哈希表和位图是数据结构中常用的两种技术。哈希表是一种数据结构,通过哈希函数把数据和位置进行映射,…...
React入门使用 (官方文档向 Part1)
文章目录 React组件:万物皆组件 JSX: 将标签引入 JavaScriptJSX 规则1. 只能返回一个根元素2. 标签必须闭合3. 使用驼峰式命名法给 ~~所有~~ 大部分属性命名!高级提示:使用 JSX 转化器 在 JSX 中通过大括号使用 JavaScript使用引号传递字符串使用大括号&…...
87基于matlab的双卡尔曼滤波算法
基于matlab的双卡尔曼滤波算法。第一步使用了卡尔曼滤波算法,用电池电压来修正SOC,然后将修正后的SOC作为第二个卡尔曼滤波算法的输入,对安时积分法得到的SOC进行修正,最终得到双卡尔曼滤波算法SOC估计值。结合EKF算法和安时积分法…...
Jacobi迭代与SOR迭代求解希尔伯特矩阵
给出线性方程组 Hn*x b,其中系数矩阵Hn为希尔伯特矩阵: 假设 x ∗ (1, 1, . . . , 1)T,b Hnx ∗。若取 n 6,8, 10,分别用 Jacobi 迭代法及 SOR迭代(ω 1, 1:25,1:5)求解,比较计算结果。…...
【云备份】配置加载文件模块
文章目录 配置信息设计配置文件加载cloud.conf配置文件单例模式的使用ReadConfigFile —— 读取配置文件GetInstance —— 创建对象其他函数的实现 具体实现cloud.confconfig.hpp 配置信息设计 使用文件配置加载一些程序运行的关键信息 可以让程序的运行更加灵活 配置信息&am…...
sqlserver写入中文乱码问题
sqlserver写入中文乱码问题解决方案 首先查看sqlserver数据库编码 首先查看sqlserver数据库编码 查询语句:SELECT COLLATIONPROPERTY(Chinese_PRC_Stroke_CI_AI_KS_WS, CodePage); 对应的编码: 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 构建系统是嵌入式软件团队实现其开发流程现代化的基础。构建系统不仅允许开发人员选择各种构建目标,还可以将这些构建集成到持续集成/持续部署 (CI/CD) 流程中。使用诸如 ChatGPT 这样的人工智能 (AI) 工…...
嵌入式设备摄像头基础知识
工作原理 摄像头的工作原理是,当光线通过镜头聚焦到图像传感器上时,传感器会将光信号转换为电信号,并将其传输给处理器进行处理。处理器通过算法对图像信号进行增强、去噪、压缩等操作,并将其转换为数字信号输出给计算机或其他设…...
使用Pytorch从零开始构建Normalizing Flow
归一化流 (Normalizing Flow) (Rezende & Mohamed,2015)学习可逆映射 f : X → Z f: X \rightarrow Z f:X→Z, 在这里X是我们的数据分布,Z是选定的潜在分布。 归一化流是生成模型家族的一部分,其中包括变分自动编…...
一个tomcat中部署的多个war,相当于几个jvm
请直接去看原文 原文链接:一个tomcat有几个jvm-CSDN博客 --------------------------------------------------------------------------------------------------------------------------------- 前几天向unmi提问,今天他答复了。我觉得答复很清楚,…...
2023年第十六届中国系统架构师大会(SACC2023)-核心PPT资料下载
一、峰会简介 本届大会以“数字转型 架构演进”为主题, 涵盖多个热门领域,如多云多活、海量分布式存储、容器、云成本、AIGC大数据等,同时还关注系统架构在各个行业中的应用,如金融、制造业、互联网、教育等。 与往届相比&#…...
高校大学校园后勤移动报修系统 微信小程序uniapp+vue
本文主要是针对线下校园后勤移动报修传统管理方式中管理不便与效率低的缺点,将电子商务和计算机技术结合起来,开发出管理便捷,效率高的基于app的大学校园后勤移动报修app。该系统、操作简单、界面友好、易于管理和维护;而且对后勤…...
docker常见问题汇总
docker常见问题 ❓问题1:启动docker容器时,报错Unknown runtime specified nvidia. 当我启动一个容器时,运行以下命令: docker run --runtimenvidia 。。。。 后面一部分命令没写出来,此时报错的信息如下:…...
JMeter 测试脚本编写技巧
JMeter 是一款开源软件,用于进行负载测试、性能测试及功能测试。测试人员可以使用 JMeter 编写测试脚本,模拟多种不同的负载情况,从而评估系统的性能和稳定性。以下是编写 JMeter 测试脚本的步骤。 第 1 步:创建测试计划 在JMet…...
力扣6:N字形变化
代码: class Solution { public:string convert(string s, int numRows){int lens.size();if(numRows1){return s;}int d2*numRows-2;int count0;string ret;//第一行!for(int i0;i<len;id){rets[i];}//第k行!for(int i1;i<numRows-1;…...
【上海大学数字逻辑实验报告】一、基本门电路
一、 实验目的 熟悉TTL中、小规模集成电路的外形、管脚和使用方法;了解和掌握基本逻辑门电路的输入与输出之间的逻辑关系及使用规则。 二、 实验原理 实现基本逻辑运算和常用逻辑运算的单元电路称为逻辑门电路。门电路通常用高电平VH表示逻辑值“1”,…...
基于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-面向对象(进阶)-面向对象的特征三:多态性_哔哩哔哩_bilibili 1.多态(仅限方法) 父类引用指向子类对象。 调用重写的方法,就会执行子类重写的方法。 编译看引用表面类型,执行看实际变量类型。 2.父子同名属性是否…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...
