UIGUソースコード解析13:MaskGraphic

ソースコード 13: マスクグラフィック

public abstract class MaskableGraphic : Graphic, IClippable, IMaskable, IMaterialModifier
{
	...    
}

画像 テキスト RawImage は MaskGraphic を継承しており、基本的に表示できる UI コンポーネントはすべて MaskGraphic を継承します。

Graphic の継承に加えて、MaskableGraphic は 3 つのインターフェースも継承します


Iクリッパブル

IClippable クリッパーは通常、クリッパー IClipper と一緒に使用されます。IClippable インターフェイスのソース コード コメントを参照してください。

   public interface IClippable
    {
        /// <summary>
        ///可被裁剪的对象
        /// GameObject of the IClippable object
        /// </summary>
        GameObject gameObject { get; }

        /// <summary>
        ///可被裁剪的父对象状态发生变化的时候使用
        /// Will be called when the state of a parent IClippable changed.
        /// </summary>
        void RecalculateClipping();

        /// <summary>
        /// 可被裁剪的对象RectTransform
        /// The RectTransform of the clippable.
        /// </summary>
        RectTransform rectTransform { get; }

        /// <summary>
        /// 在给给定的裁剪范围中进行裁剪计算
        /// Clip and cull the IClippable given a specific clipping rect
        /// </summary>
        /// <param name="clipRect">The Rectangle in which to clip against.</param>
        /// <param name="validRect">Is the Rect valid. If not then the rect has 0 size.</param>
        void Cull(Rect clipRect, bool validRect);

        /// <summary>
        /// 设置可被裁剪的对象的裁剪范围
        /// Set the clip rect for the IClippable.
        /// </summary>
        /// <param name="value">The Rectangle for the clipping</param>
        /// <param name="validRect">Is the rect valid.</param>
        void SetClipRect(Rect value, bool validRect);

        /// <summary>
        /// Set the clip softness for the IClippable.
        ///
        /// The softness is a linear alpha falloff over clipSoftness pixels.
        /// </summary>
        /// <param name="clipSoftness">The number of pixels to apply the softness to </param>
        void SetClipSoftness(Vector2 clipSoftness);
        

IClipper には現在 RectMask2D コンポーネント継承の実装のみがあります

つまり、通常、トリミングする場合、カッター RectMask2D はカッター MaskableGraphic に切り取り長方形を設定します。


ここではまず、MaskGraphic がアプリケーションのトリミング関連コンテンツを設定する方法と、RectMask2D でそれをトリミングする方法を分析します。

SetClipRect MaskableGraphic は、クリッピング四角形を CanvasRenderer レンダラーに送信します。

public virtual void SetClipRect(Rect clipRect, bool validRect)
{
    if (validRect)
        canvasRenderer.EnableRectClipping(clipRect);
    else
        canvasRenderer.DisableRectClipping();
}

RecalculateClipping は、親オブジェクトの RectMask2D コンポーネント (m_ParentMask) を再計算します。

/// <summary>
    /// See IClippable.RecalculateClipping
    /// </summary>
    public virtual void RecalculateClipping()
    {
        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;
	}

Cull カリングメソッド validRect が false の場合、または入力された ClipRect が Canvas の長方形領域と一致しない場合は、UpdateCull メソッドを呼び出し、cull を true に設定し、canvasRenderer.cull に cull を代入します。CanvasRenderer.cull が変更された場合は、イベント m_OnCullStateChanged、m_OnCullStateChanged.Invoke(cull) を送信し、SetVerticesDirty を呼び出して頂点の Dirty を設定し、再描画を待ちます。

    public virtual void Cull(Rect clipRect, bool validRect)
    {
        var cull = !validRect || !clipRect.Overlaps(rootCanvasRect, true);
        UpdateCull(cull);
    }

    private void UpdateCull(bool cull)
    {
        if (canvasRenderer.cull != cull)
        {
            canvasRenderer.cull = cull;
            UISystemProfilerApi.AddMarker("MaskableGraphic.cullingChanged", this);
            m_OnCullStateChanged.Invoke(cull);
            OnCullingChanged();
        }
    }

Iマスカブル

IMaskable マスクされた人物は IClippable に似ており、マスカー Mask コンポーネントもあります (MaskGraphic コンポーネントが必要です)。

ここでは IMaskable Mask としてのみ分析し、後で分析します。

IMaskable には実装メソッド RecalculateMasking が 1 つだけあります

        public virtual void RecalculateMasking()
        {
            // Remove the material reference as either the graphic of the mask has been enable/ disabled.
            // This will cause the material to be repopulated from the original if need be. (case 994413)
            StencilMaterial.Remove(m_MaskMaterial);
            m_MaskMaterial = null;
            m_ShouldRecalculateStencil = true;
            SetMaterialDirty();
        }

m_ShouldRecalculateStencil を true に設定し、SetmaterialDirty を呼び出します。つまり、Mask が有効な場合、すべての IMaskable サブオブジェクトの StencilValue が変更され、再構築がマークされます。

Iマテリアルモディファイア

MaskGraphic は、マスキング効果がマテリアルを通じて実現されるため、主にマスキング効果を実現するために使用される IMaterialModifier インターフェイスも実装します。

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

            if (m_ShouldRecalculateStencil)
            {
                if (maskable)
                {
                    var rootCanvas = MaskUtilities.FindRootSortOverrideCanvas(transform);
                    m_StencilValue = MaskUtilities.GetStencilDepth(transform, rootCanvas);
                }
                else
                    m_StencilValue = 0;

                m_ShouldRecalculateStencil = false;
            }

            // if we have a enabled Mask component then it will
            // generate the mask material. This is an optimization
            // it adds some coupling between components though :(
            if (m_StencilValue > 0 && !isMaskingGraphic)
            {
                var maskMat = StencilMaterial.Add(toUse, (1 << m_StencilValue) - 1, StencilOp.Keep, CompareFunction.Equal, ColorWriteMask.All, (1 << m_StencilValue) - 1, 0);
                StencilMaterial.Remove(m_MaskMaterial);
                m_MaskMaterial = maskMat;
                toUse = m_MaskMaterial;
            }
            return toUse;
        }

GetModifiedmaterial メソッドは、マークされて再構築された後、Rebulid で呼び出されます。

テンプレートを再計算する必要がある場合は、overrideSorting が true の Canvas を親 RectTransform から取得し、rootCanvas に割り当ててから、MaskUtilities.GetStencilDepth を通じて rootCanvas からテンプレートの深さを取得します。

テンプレートの深さが 0 より大きく、Mask コンポーネントが存在しないか、Mask コンポーネントがアクティブ化されていない場合は、basematerial、stencilID、operation、およびその他のパラメータを Stencilmaterial に追加し、Stencilmaterial から古い m_Maskmaterial を削除し、m_Maskmaterial を新しい Basematerial に置き換えます。戻る


その他のサプリメント

  protected override void OnEnable()
    {
        base.OnEnable();
        m_ShouldRecalculateStencil = true;
        UpdateClipParent();
        SetMaterialDirty();

        if (isMaskingGraphic)
        {
            MaskUtilities.NotifyStencilStateChanged(this);
        }
    }

コンポーネントが最初にアクティブ化されるときに、再計算テンプレート フラグを True に設定し、クリップされた親オブジェクトを更新し、マテリアルを Dirty に設定し、SetMaterialDirty を設定します。Stencilmaterial から m_Maskmaterial を削除し、m_Maskmaterial を空に設定しました。Makk コンポーネントが空でない場合は、MaskUtilities.NotifyStencilStateChanged を呼び出してマスクを再計算します。

   protected override void OnDisable()
    {
        base.OnDisable();
        m_ShouldRecalculateStencil = true;
        SetMaterialDirty();
        UpdateClipParent();
        StencilMaterial.Remove(m_MaskMaterial);
        m_MaskMaterial = null;

        if (isMaskingGraphic)
        {
            MaskUtilities.NotifyStencilStateChanged(this);
        }
    }

再計算テンプレート m_ShouldRecalculateStencil を true に設定し、クリップされた親オブジェクト UpdateClipParent を更新し、マテリアルを Dirty に設定し、SetmaterialDirty に設定します。Stencilmaterial から m_Maskmaterial を削除し、m_Maskmaterial を空に設定しました。Mesh コンポーネントが空でない場合は、MaskUtilities.NotifyStencilStateChanged を呼び出してマスクを再計算します。


ステンシルマテリアルクラス

    /// <summary>
    /// Dynamic material class makes it possible to create custom materials on the fly on a per-Graphic basis,
    /// and still have them get cleaned up correctly.
    /// </summary>
    public static class StencilMaterial
    {
       	private static List<MatEntry> m_List = new List<MatEntry>();
    	...
    }

StencilMaterial は、テンプレート マテリアルの管理を担当する静的クラスです。MatEntry タイプのリストを維持します。

プライベート静的リスト m_List = new List();

Add、Remove、および ClearAll メソッドを外部から呼び出して、この List を操作できます。

Add メソッドは、MatEntry を作成し、入力ベースマットとその他のパラメーターを MatEntry に割り当て、ベースマットを割り当てるカスタムマットを作成し、ステンシル ID や操作などのパラメーターをカスタムマットに割り当てます。実際には、カスタムマットのシェーダー パラメーターが割り当てられます。 。

おすすめ

転載: blog.csdn.net/NippyLi/article/details/123514436