传入 RectMask2D 列表,计算出他们重叠部分的区域 ///<summary> /// Find the Rect to use for clipping. /// Given the input RectMask2ds find a rectangle that is the overlap of all the inputs. ///</summary> ///<param name="rectMaskParents">RectMasks to build the overlap rect from.</param> ///<param name="validRect">Was there a valid Rect found.</param> ///<returns>The final compounded overlapping rect</returns> publicstatic Rect FindCullAndClipWorldRect(List<RectMask2D> rectMaskParents, outbool validRect) { if (rectMaskParents.Count == 0) { validRect = false; returnnew Rect(); }
Rect current = rectMaskParents[0].canvasRect; float xMin = current.xMin; float xMax = current.xMax; float yMin = current.yMin; float yMax = current.yMax; for (var i = 1; i < rectMaskParents.Count; ++i) { current = rectMaskParents[i].canvasRect; if (xMin < current.xMin) xMin = current.xMin; if (yMin < current.yMin) yMin = current.yMin; if (xMax > current.xMax) xMax = current.xMax; if (yMax > current.yMax) yMax = current.yMax; }
///<summary> ///Method that handles calculations of canvas scaling. ///</summary> protectedvirtualvoidHandle() { if (m_Canvas == null || !m_Canvas.isRootCanvas) return;
if (m_Canvas.renderMode == RenderMode.WorldSpace) { HandleWorldCanvas(); return; }
switch (m_UiScaleMode) { case ScaleMode.ConstantPixelSize: HandleConstantPixelSize(); break; case ScaleMode.ScaleWithScreenSize: HandleScaleWithScreenSize(); break; case ScaleMode.ConstantPhysicalSize: HandleConstantPhysicalSize(); break; } }
///<summary> /// Handles canvas scaling that scales with the screen size. ///</summary> protectedvirtualvoidHandleScaleWithScreenSize() { Vector2 screenSize = new Vector2(Screen.width, Screen.height);
// Multiple display support only when not the main display. For display 0 the reported // resolution is always the desktops resolution since its part of the display API, // so we use the standard none multiple display method. (case 741751) int displayIndex = m_Canvas.targetDisplay; if (displayIndex > 0 && displayIndex < Display.displays.Length) { Display disp = Display.displays[displayIndex]; screenSize = new Vector2(disp.renderingWidth, disp.renderingHeight); }
float scaleFactor = 0; switch (m_ScreenMatchMode) { case ScreenMatchMode.MatchWidthOrHeight: { // We take the log of the relative width and height before taking the average. // Then we transform it back in the original space. // the reason to transform in and out of logarithmic space is to have better behavior. // If one axis has twice resolution and the other has half, it should even out if widthOrHeight value is at 0.5. // In normal space the average would be (0.5 + 2) / 2 = 1.25 // In logarithmic space the average is (-1 + 1) / 2 = 0 float logWidth = Mathf.Log(screenSize.x / m_ReferenceResolution.x, kLogBase); float logHeight = Mathf.Log(screenSize.y / m_ReferenceResolution.y, kLogBase); float logWeightedAverage = Mathf.Lerp(logWidth, logHeight, m_MatchWidthOrHeight); scaleFactor = Mathf.Pow(kLogBase, logWeightedAverage); break; } case ScreenMatchMode.Expand: { scaleFactor = Mathf.Min(screenSize.x / m_ReferenceResolution.x, screenSize.y / m_ReferenceResolution.y); break; } case ScreenMatchMode.Shrink: { scaleFactor = Mathf.Max(screenSize.x / m_ReferenceResolution.x, screenSize.y / m_ReferenceResolution.y); break; } }
IMaterialModifier.cs ///<summary> /// Interface which allows for the modification of the Material used to render a Graphic before they are passed to the CanvasRenderer. ///</summary> ///<remarks> /// When a Graphic sets a material is is passed (in order) to any components on the GameObject that implement IMaterialModifier. This component can modify the material to be used for rendering. ///</remarks> publicinterfaceIMaterialModifier { ///<summary> /// Perform material modification in this function. ///</summary> ///<param name="baseMaterial">The material that is to be modified</param> ///<returns>The modified material.</returns> Material GetModifiedMaterial(Material baseMaterial); }
MaskableGraphic.cs ///<summary> /// See IMaterialModifier.GetModifiedMaterial ///</summary> publicvirtual Material GetModifiedMaterial(Material baseMaterial) { var toUse = baseMaterial;
if (m_ShouldRecalculateStencil) { var rootCanvas = MaskUtilities.FindRootSortOverrideCanvas(transform); m_StencilValue = maskable ? MaskUtilities.GetStencilDepth(transform, rootCanvas) : 0; m_ShouldRecalculateStencil = false; }
// if we have a enabled Mask component then it will // generate the mask material. This is an optimisation // it adds some coupling between components though :( Mask maskComponent = GetComponent<Mask>(); if (m_StencilValue > 0 && (maskComponent == null || !maskComponent.IsActive())) { var maskMat = StencilMaterial.Add(toUse, (1 << m_StencilValue) - 1, StencilOp.Keep, CompareFunction.Equal, ColorWriteMask.All, (1 << m_StencilValue) - 1, 0); StencilMaterial.Remove(m_MaskMaterial); m_MaskMaterial = maskMat; toUse = m_MaskMaterial; } return toUse; }
SpecializedCollections 收集
IndexedSet
//This is a container that gives: // - Unique items // - Fast random removal // - Fast unique inclusion to the end // - Sequential access //Downsides: // - Uses more memory // - Ordering is not persistent // - Not Serialization Friendly.
///<summary> /// Duplicate vertices from start to end and turn them into shadows with the given offset. ///</summary> ///<param name="verts">Vert list to copy</param> ///<param name="color">Shadow color</param> ///<param name="start">The start index in the verts list</param> ///<param name="end">The end index in the vers list</param> ///<param name="x">The shadows x offset</param> ///<param name="y">The shadows y offset</param> protectedvoidApplyShadow(List<UIVertex> verts, Color32 color, int start, int end, float x, float y) { ApplyShadowZeroAlloc(verts, color, start, end, x, y); }
protectedvoidApplyShadowZeroAlloc(List<UIVertex> verts, Color32 color, int start, int end, float x, float y) { UIVertex vt;
var neededCapacity = verts.Count + end - start; if (verts.Capacity < neededCapacity) verts.Capacity = neededCapacity;
for (int i = start; i < end; ++i) { vt = verts[i]; verts.Add(vt);
///<summary> /// Try and add the given element to the rebuild list. /// Will not return if successfully added. ///</summary> ///<param name="element">The element that is needing rebuilt.</param> publicstaticvoidRegisterCanvasElementForGraphicRebuild(ICanvasElement element) { instance.InternalRegisterCanvasElementForGraphicRebuild(element); }
privateboolInternalRegisterCanvasElementForGraphicRebuild(ICanvasElement element) { if (m_PerformingGraphicUpdate) { Debug.LogError(string.Format("Trying to add {0} for graphic rebuild while we are already inside a graphic rebuild loop. This is not supported.", element)); returnfalse; }
// 计算并设置裁剪的范围,再对所有子节点调用裁剪操作 publicvirtualvoidPerformClipping() { if (ReferenceEquals(Canvas, null)) { return; }
//TODO See if an IsActive() test would work well here or whether it might cause unexpected side effects (re case 776771)
// if the parents are changed // or something similar we // do a recalculate here if (m_ShouldRecalculateClipRects) { // 获取所有有关联的RectMask2D Mask范围 MaskUtilities.GetRectMasksForClip(this, m_Clippers); m_ShouldRecalculateClipRects = false; }
// get the compound rects from // the clippers that are valid bool validRect = true; // 计算需要裁剪的部分,实际上是计算不需要裁剪的部分没其他部分都进行裁剪 Rect clipRect = Clipping.FindCullAndClipWorldRect(m_Clippers, out validRect);
// If the mask is in ScreenSpaceOverlay/Camera render mode, its content is only rendered when its rect // overlaps that of the root canvas. RenderMode renderMode = Canvas.rootCanvas.renderMode; bool maskIsCulled = (renderMode == RenderMode.ScreenSpaceCamera || renderMode == RenderMode.ScreenSpaceOverlay) && !clipRect.Overlaps(rootCanvasRect, true);
if (maskIsCulled) { // Children are only displayed when inside the mask. If the mask is culled, then the children // inside the mask are also culled. In that situation, we pass an invalid rect to allow callees // to avoid some processing. clipRect = Rect.zero; validRect = false; }
if (clipRect != m_LastClipRectCanvasSpace) { foreach (IClippable clipTarget in m_ClipTargets) { // 对所有需要裁剪的UI元素进行裁剪操作 clipTarget.SetClipRect(clipRect, validRect); }