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);
}

 

posted @ 2023-01-23 15:32  yanghui01  阅读(127)  评论(0编辑  收藏  举报