UGUI之MaskableGraphic
阅读原文时间:2023年07月11日阅读:1

MaskableGraphic继承自Graphic,并且继承了IClippable, IMaskable, IMaterialModifier三个接口。它是RawImage、Image和Text的父类。

继承自Graphic的方法:

OnEnable:设置m_ShouldRecalculateStencil(是否需要重新计算模板)为true,调用UpdateClipParent(更新裁剪的父对象),调用SetMaterialDirty(设置材质为脏,Graphic的函数)。若有Mask组件,调用静态函数MaskUtilities.NotifyStencilStateChanged,重新计算Mask。

OnDisable:设置m_ShouldRecalculateStencil为true,依次调用 SetMaterialDirty和UpdateClipParent。在StencilMaterial中移除m_MaskMaterial,并把m_MaskMaterial设为null。若有Mask组件,调用静态函数MaskUtilities.NotifyStencilStateChanged。

OnTransformParentChanged(当父对象改变):设置 m_ShouldRecalculateStencil为true,依次调用UpdateClipParent、SetMaterialDirty。

OnCanvasHierarchyChanged(父对象的Canvas状态改变):设置 m_ShouldRecalculateStencil为true,依次调用UpdateClipParent、SetMaterialDirty。

看一下UpdateClipParent的代码:

     private void UpdateClipParent()
{
var newParent = (maskable && IsActive()) ? MaskUtilities.GetRectMaskForClippable(this) : null;

        // if the new parent is different OR is now inactive  
        if (m\_ParentMask != null && (newParent != m\_ParentMask || !newParent.IsActive()))  
        {  
            m\_ParentMask.RemoveClippable(this);  
            UpdateCull(false);  
        }

        // don't re-add it if the newparent is inactive  
        if (newParent != null && newParent.IsActive())  
            newParent.AddClippable(this);

        m\_ParentMask = newParent;  
    }

调用MaskUtilities.GetRectMaskForClippable找到父对象的RectMask2D组件(RectMask2D组件可以根据RectTransform裁剪子对象,子对象超出父RectTransform范围的部分会被裁剪掉)。

如果newParent不等于m_ParentMask或者newParent是未激活的,就调用RemoveClippable(在RemoveClippable中调用clippable.SetClipRect(new Rect(), false)关闭矩形裁剪,并且把自己从RectMask2D的m_ClipTargets中删除),然后更新剔除。

如果newParent激活,就调用AddClippable(把自己添加到RectMask2D的m_ClipTargets中)。

把newParent赋值给m_ParentMask。

继承自IClippable的方法:

RecalculateClipping(当父对象的IClippable状态改变时调用):调用UpdateClipParent。

Cull:如果validRect为false或者clipRect与rootCanvasRect矩形不重合,调用UpdateCull。UpdateCull中,如果canvasRenderer.cull不等于输入的cull,则canvasRenderer.cull=cull,回调m_OnCullStateChanged,再调用Graphic的OnCullingChanged函数。

SetClipRect:根据传入的validRect值,选择开启或者关闭canvasRenderer的矩形裁剪。

继承自IMaskable的方法:

RecalculateMasking:在StencilMaterial中移除m_MaskMaterial,把m_MaskMaterial设为null,m_ShouldRecalculateStencil设为true,调用SetMaterialDirty函数。

继承自IMaterialModifier的方法:

     public virtual Material GetModifiedMaterial(Material baseMaterial)
{
var toUse = baseMaterial;

        if (m\_ShouldRecalculateStencil)  
        {  
            var rootCanvas = MaskUtilities.FindRootSortOverrideCanvas(transform);  
            m\_StencilValue = maskable ? MaskUtilities.GetStencilDepth(transform, rootCanvas) : ;  
            m\_ShouldRecalculateStencil = false;  
        }

        // if we have a enabled Mask component then it will  
        // generate the mask material. This is an optimisation  
        // it adds some coupling between components though :(  
        Mask maskComponent = GetComponent<Mask>();  
        if (m\_StencilValue >  && (maskComponent == null || !maskComponent.IsActive()))  
        {  
            var maskMat = StencilMaterial.Add(toUse, ( << m\_StencilValue) - , StencilOp.Keep, CompareFunction.Equal, ColorWriteMask.All, ( << m\_StencilValue) - , );  
            StencilMaterial.Remove(m\_MaskMaterial);  
            m\_MaskMaterial = maskMat;  
            toUse = m\_MaskMaterial;  
        }  
        return toUse;  
    }

GetModifiedMaterial:如果m_ShouldRecalculateStencil为true,通过MaskUtilities.FindRootSortOverrideCanvas获取rootCanvas,根据maskable,给m_StencilValue赋值为模板深度或者0,m_ShouldRecalculateStencil设为false。

如果 m_StencilValue大于0且Mask组件不存在或者未激活,就把baseMaterial,stencilID,operation等参数添加到StencilMaterial中,并把m_MaskMaterial替换成新的材质。

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章