ソースコード 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 や操作などのパラメーターをカスタムマットに割り当てます。実際には、カスタムマットのシェーダー パラメーターが割り当てられます。 。