• (八)RectMask2D详解


    1.前言

    RectMaskD的基本原理就是CanvasRenderer的EnableRectClipping方法,上一节已经做了详细说明。而它的工作流程在(六)(五)中也做了详细分析。此篇重新梳理一下流程,做更细致的分析。

    2.详解

    RectMask2D的基本原理比较建议,复杂点在于其上层逻辑比较复杂,今天就按逻辑顺序进行分析。
    1)启动时通过ClipperRegistry.Register(this);将自己注册到RectMask2D的管理类ClipperRegistry中,便于后续统一调用(CLipperRegistry参与整个Canvas的运作流程,所以可以参考此文的流程图以及2.3节的分析)。
    2)启动的同时通过 MaskUtilities.Notify2DMaskStateChanged(this)通知所有子游戏物体(继承IClippable,后续简称子Clippable)重新更新Clipp状态(通过UpdateClipParent重新确定影响自身Clip的RectMask2D);由于考虑到会存在多个Canvas以及RectMask2D的情况,所以子Clippable在得到重新更新状态通知时,会调用MaskUtilities.GetRectMaskForClippable方法重新确认RectMask2D。确认后每个子Clippable将自己添加到相应的RectMask2D维护的列表中。

            public static void Notify2DMaskStateChanged(Component mask)
            {
                var components = ListPool<Component>.Get();
                mask.GetComponentsInChildren(components);
                for (var i = 0; i < components.Count; i++)
                {
                    if (components[i] == null || components[i].gameObject == mask.gameObject)
                        continue;
    
                    var toNotify = components[i] as IClippable;
                    if (toNotify != null)
                        toNotify.RecalculateClipping();
                }
                ListPool<Component>.Release(components);
            }
    

    以上两步为逻辑层控制实现子游戏物体mask的基础。后续是实现mask的方法。


    3)当Canvas更新时会调用ClipperRegistry的cull方法进行剔除(即实现遮罩),如下所示。cull方法会通知所有的RectMask2D进行PerformClipping。

           public void Cull()
            {
                for (var i = 0; i < m_Clippers.Count; ++i)
                {
                    m_Clippers[i].PerformClipping();
                }
            }
    

    4)当RectMask2D收到PerformClipping命令时,先获取所有父类有效的RectMask2D。这是为了后续计算遮罩的范围Rect。因为当有两个RectMask2D时,裁切范围是两个共同作用的区域。然后采用Clipping.FindCullAndClipWorldRect方法计算裁切区域。通过名字也可以知道,计算出来的rect为world级别的(其实就是对应的Canvas下的坐标值)。

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

    其中比较有用的一个方法是计算两个rect的相交范围:

            private static Rect RectIntersect(Rect a, Rect b)
            {
                float xMin = Mathf.Max(a.x, b.x);
                float xMax = Mathf.Min(a.x + a.width, b.x + b.width);
                float yMin = Mathf.Max(a.y, b.y);
                float yMax = Mathf.Min(a.y + a.height, b.y + b.height);
                if (xMax >= xMin && yMax >= yMin)
                    return new Rect(xMin, yMin, xMax - xMin, yMax - yMin);
                return new Rect(0f, 0f, 0f, 0f);
            }
    

    5)当确定了裁切范围后,RectMask2D通知自己维护的IClippable列表成员进行裁切,然后每个IClippable列表成员调用 canvasRenderer.EnableRectClipping(clipRect);进行裁切。

    以上为基本流程,真是代码中会考虑其他一些状况。比如第五步并非一定会进行裁切,而是会根据条件选择裁切或者不进行裁切。

    3.结语

    以上为RectMask2D裁切的详细流程分析。

  • 相关阅读:
    LIBSVM使用介绍
    Symbian开发平台的搭建之VC++6.0&&Carbide C++ 2.0
    traits:Traits技术初探
    SDK与IDE的选择(附上设置默认SDK)
    浅析COM的思想及原理
    Windows Live Writer 支持的博客
    JQuery笔记(四) 通用选择的尝试
    JQuery笔记(一)
    JQuery笔记(二) animate支持的属性
    在DW绿化版或者精简版中使用扩展管理
  • 原文地址:https://www.cnblogs.com/llstart-new0201/p/12678699.html
Copyright © 2020-2023  润新知