UIGU source code analysis 15: Mask

Source code 15: Mask

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

    [SerializeField]
    private bool m_ShowMaskGraphic = true;

	...

}

The Mask component inherits UIBehaviour and implements two interfaces ICanvasRaycastFilter and IMaterialModifier.

ICanvasRaycastFilter: Whether the RectTransform contains the point seen from the camera

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

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

IMaterialModifier: Inherited from the IMaterialModifier interface, MaskableGraphic also inherits this interface. This method is used to modify the obtained material to achieve the masking effect.


Similar to RectMask2D, the use of Mask must be coordinated with the masked IMaskable, which is the MaskableGraphic component. But unlike the RectMask2D component, Mask must be bound to a Graphic for masking. The components displayed in UGUI basically inherit the MaskableGraphic component, which means that when MaskableGraphic is used as a mask, a Mask component needs to be bound. At the same time, Text and Image are masked when they are responsible for display. MaskableGraphic has attributes to distinguish it.

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

The assignment of isMaskingGraphic is when binding the Mask component. It is set to True when the Mask component is activated and set to False when it is closed.

Mask code:

    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(); is to set the label for rebuild to True. Analyzing Graphics was discussed earlier.

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) notifies all sub-objects that implement IMaskable to recalculate the mask. In fact, I finally returned to Graphic to call SetMaterialDirty, update the material UpdateMaterial, and modify the vertex data and material data of Graphic. This is why MaskableGraphic needs to implement IMaterialModifier.

Guess you like

Origin blog.csdn.net/NippyLi/article/details/123601941