UIGU源码分析15:Mask

源码15:Mask

public class Mask : UIBehaviour, ICanvasRaycastFilter, IMaterialModifier
{
    [NonSerialized]
    private RectTransform m_RectTransform;

    [SerializeField]
    private bool m_ShowMaskGraphic = true;

	...

}

Mask 组件继承UIBehaviour 同时要实现两个接口ICanvasRaycastFilter, IMaterialModifier

ICanvasRaycastFilter:RectTransform是否包含从相机看到的点

    public virtual bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera)
    {
        if (!isActiveAndEnabled)
            return true;

        return RectTransformUtility.RectangleContainsScreenPoint(rectTransform, sp, eventCamera);
    }

IMaterialModifier :继承自IMaterialModifier接口,MaskableGraphic也继承了这个接口,这个方法是用来修改获取的材质来实现遮罩效果。


与RectMask2D类似 ,Mask的使用要配合被遮罩者IMaskable,也就是MaskableGraphic组件。但是和RectMask2D组件不同,Mask必须绑定一个Graphic用来做遮罩。UGUI里显示的组件基本都是继承MaskableGraphic组件的,也就是说MaskableGraphic作为遮罩的时候就需要绑定一个Mask组件。同时Text、Image负责显示的时候又是被遮罩者。MaskableGraphic有属性做了区分。

    /// <summary>
    /// Is this graphic the graphic on the same object as a Mask that is enabled.
    /// </summary>
    /// <remarks>
    /// If toggled ensure to call MaskUtilities.NotifyStencilStateChanged(this); manually as it changes how stenciles are calculated for this image.
    /// </remarks>
    public bool isMaskingGraphic
    {
        get { return m_IsMaskingGraphic; }
        set
        {
            if (value == m_IsMaskingGraphic)
                return;

            m_IsMaskingGraphic = value;
        }
    }

isMaskingGraphic的赋值就是在绑定Mask组件的时候 ,当Mask组件激活时设置为True,关闭的时候设置为False。

Mask代码:

    protected override void OnEnable()
    {
        base.OnEnable();
        if (graphic != null)
        {
            graphic.canvasRenderer.hasPopInstruction = true;
            graphic.SetMaterialDirty();

            // Default the graphic to being the maskable graphic if its found.
            if (graphic is MaskableGraphic)
                (graphic as MaskableGraphic).isMaskingGraphic = true;
        }

        MaskUtilities.NotifyStencilStateChanged(this);
    }

    protected override void OnDisable()
    {
        // we call base OnDisable first here
        // as we need to have the IsActive return the
        // correct value when we notify the children
        // that the mask state has changed.
        base.OnDisable();
        if (graphic != null)
        {
            graphic.SetMaterialDirty();
            graphic.canvasRenderer.hasPopInstruction = false;
            graphic.canvasRenderer.popMaterialCount = 0;

            if (graphic is MaskableGraphic)
                (graphic as MaskableGraphic).isMaskingGraphic = false;
        }

        StencilMaterial.Remove(m_MaskMaterial);
        m_MaskMaterial = null;
        StencilMaterial.Remove(m_UnmaskMaterial);
        m_UnmaskMaterial = null;

        MaskUtilities.NotifyStencilStateChanged(this);
    }

graphic.SetMaterialDirty(); 是设置进行rebuild的标签为True 。分析Graphic是的时候讲过。

public static void NotifyStencilStateChanged(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 IMaskable;
            if (toNotify != null)
                toNotify.RecalculateMasking();
        }
        ListPool<Component>.Release(components);
    }

MaskUtilities.NotifyStencilStateChanged(this) 通知所有实现了IMaskable的子物体重新计算遮罩。其实最终还是回到了Graphic中 调用SetMaterialDirty,更新材质UpdateMaterial,修改Graphic的顶点数据以及材质数据。这也就是为什么MaskableGraphic 需要实现IMaterialModifier的原因。

猜你喜欢

转载自blog.csdn.net/NippyLi/article/details/123601941