RectMask2D裁剪区域计算
裁剪区域计算涉及的几种情况
1) 只有一个RectMask2D时,裁剪区域就是RectMask2D所在的区域
2) RectMask2D嵌套RectMask2D时:
a) RectMask2D(红色)的祖先节点中没有RectMask2D了,所以裁剪区域就是自己所在的矩形区域。
b) RectMask2D_2(绿色)的祖先节点中有1个RectMask2D,所以裁剪区域为:RectMask2D_2和RectMask2D矩形区域相交(intersect)后的结果。
c) RectMask2D_3(蓝色)的祖先节点中有2个RectMask2D,所以裁剪区域为:RectMask2D_3, RectMask2D_2和RectMask2D矩形区域相交(intersect)后的结果。
3) RectMask2D嵌套RectMask2D,并且祖先节点有Canvas(且overrideSorting为true):
a) RectMask2D(红色)的祖先节点中没有RectMask2D了,所以裁剪区域就是自己所在的矩形区域。
b) RectMask2D_2(绿色)的祖先节点中有1个RectMask2D,所以裁剪区域为:RectMask2D_2和RectMask2D矩形区域相交(intersect)后的结果。
c) RectMask2D_3(蓝色)的祖先节点中有2个RectMask2D,但是RectMask2D_3的父节点Canvas_2的存在,导致RectMask2D和RectMask2D_2不参与裁剪区域相交计算(因为Canvas_1是RectMask2D的子孙节点,也是RectMask2D_2的子孙节点)。所以裁剪区域为RectMask2D_3所在的矩形区域。
d) RectMask2D_4(紫色)的祖先节点中有2个RectMask2D,所以裁剪区域为:RectMask2D_4, RectMask2D_2和RectMask2D矩形区域相交(intersect)后的结果。
涉及到的相关代码
RectMask2D.PerformClipping,裁剪逻辑
public virtual void PerformClipping() { 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) { 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); bool clipRectChanged = clipRect != m_LastClipRectCanvasSpace; bool forceClip = m_ForceClip; // Avoid looping multiple times. foreach (IClippable clipTarget in m_ClipTargets) { if (clipRectChanged || forceClip) { clipTarget.SetClipRect(clipRect, validRect); } var maskable = clipTarget as MaskableGraphic; if (maskable != null && !maskable.canvasRenderer.hasMoved && !clipRectChanged) continue; // 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. clipTarget.Cull( maskIsCulled ? Rect.zero : clipRect, maskIsCulled ? false : validRect); } m_LastClipRectCanvasSpace = clipRect; m_ForceClip = false; }
MaskUtilities.GetRectMasksForClip:计算哪几个RectMask2D参与裁剪
public static void GetRectMasksForClip(RectMask2D clipper, List<RectMask2D> outMasks) { outMasks.Clear(); List<RectMask2D> rectMaskComponents = ListPool<RectMask2D>.Get(); clipper.transform.GetComponentsInParent(false, rectMaskComponents); if (rectMaskComponents.Count > 0) { List<Canvas> canvasComponents = ListPool<Canvas>.Get(); clipper.transform.GetComponentsInParent(false, canvasComponents); for (int i = rectMaskComponents.Count - 1; i >= 0; i--) { var rectMaskItem = rectMaskComponents[i]; if (!rectMaskItem.IsActive()) continue; bool shouldAdd = true; //---------- RectMask2D的子孙节点中如果有Canvas, 且Canvas overrideSorting了, 就不参与裁剪区域相交计算 for (int j = canvasComponents.Count - 1; j >= 0; j--) { var canvasItem = canvasComponents[j]; if (!IsDescendantOrSelf(canvasItem.transform, rectMaskItem.transform) && canvasItem.overrideSorting) { shouldAdd = false; break; } } //---------- if (shouldAdd) outMasks.Add(rectMaskItem); } ListPool<Canvas>.Release(canvasComponents); } ListPool<RectMask2D>.Release(rectMaskComponents); }
Clipping.FindCullAndClipWorldRect:裁剪区域相交结果结算
public static Rect FindCullAndClipWorldRect(List<RectMask2D> rectMaskParents, out bool validRect) { if (rectMaskParents.Count == 0) { validRect = false; return new Rect(); } var compoundRect = rectMaskParents[0].canvasRect; for (var i = 0; i < rectMaskParents.Count; ++i) compoundRect = RectIntersect(compoundRect, rectMaskParents[i].canvasRect); var cull = compoundRect.width <= 0 || compoundRect.height <= 0; if (cull) { validRect = false; return new Rect(); } Vector3 point1 = new Vector3(compoundRect.x, compoundRect.y, 0.0f); Vector3 point2 = new Vector3(compoundRect.x + compoundRect.width, compoundRect.y + compoundRect.height, 0.0f); validRect = true; return new Rect(point1.x, point1.y, point2.x - point1.x, point2.y - point1.y); }