Skip to content

Instantly share code, notes, and snippets.

@rumaniel
Created November 11, 2025 05:12
Show Gist options
  • Select an option

  • Save rumaniel/09a022e7b59289e2b811cb60a518003d to your computer and use it in GitHub Desktop.

Select an option

Save rumaniel/09a022e7b59289e2b811cb60a518003d to your computer and use it in GitHub Desktop.
To applying RectMask2d even if Canvas override sorting.
using UnityEngine;
public class ClipRectToTarget : MonoBehaviour
{
[SerializeField] private RectTransform target;
public RectTransform Target
{
get => target;
private set
{
target = value;
if (enabled)
{
SetTargetClippingRect();
currentPos = lastPos = target.position;
}
}
}
public CanvasRenderer canvasRenderer;
private Vector2 lastPos;
private Vector2 currentPos;
private void Awake()
{
if (canvasRenderer == null) canvasRenderer = GetComponent<CanvasRenderer>();
if (target != null)
{
currentPos = lastPos = target.position;
}
}
private void Update()
{
if (target == null) return;
currentPos = target.position;
if (currentPos != lastPos)
{
SetTargetClippingRect();
}
lastPos = currentPos;
}
private void OnEnable()
{
if (target != null)
{
SetTargetClippingRect();
}
}
private void OnDisable()
{
canvasRenderer.DisableRectClipping();
}
private void SetTargetClippingRect()
{
var rect = target.rect;
Vector2 offset = target.localPosition;
Transform parent = target.parent;
while (parent.GetComponent<Canvas>() == null || !parent.GetComponent<Canvas>().isRootCanvas)
{
offset += (Vector2)parent.localPosition;
parent = parent.parent;
}
rect.x += offset.x;
rect.y += offset.y;
canvasRenderer.EnableRectClipping(rect);
}
}
/// <summary>
/// This component can affected by RectMask2d even if Canvas override Sorting.
/// </summary>
public class ForceMaskableImage : Image
{
#region Override MaskableGraphic
private RectMask2D _ParentMask;
// todo check maskable base
protected override void OnTransformParentChanged()
{
base.OnTransformParentChanged();
UpdateSet();
}
private void UpdateSet()
{
if (!isActiveAndEnabled)
return;
m_ShouldRecalculateStencil = true;
UpdateClipParentForce();
SetMaterialDirty();
}
public override void RecalculateClipping() => UpdateClipParentForce();
private void UpdateCull(bool cull)
{
if (canvasRenderer.cull != cull)
{
canvasRenderer.cull = cull;
UISystemProfilerApi.AddMarker("MaskableGraphic.cullingChanged", this);
OnCullingChanged();
}
}
private void UpdateClipParentForce()
{
var newParent = (maskable && IsActive()) ? MaskUtilities.GetRectMaskForClippable(this) : null;
// if the new parent is different OR is now inactive
if (_ParentMask != null && (newParent != _ParentMask || !newParent.IsActive()))
{
_ParentMask.RemoveClippable(this);
UpdateCull(false);
}
// don't re-add it if the newparent is inactive
if (newParent != null && newParent.IsActive())
newParent.AddClippable(this);
_ParentMask = newParent;
}
#endregion
#region Override MaskUtilities
/// <summary>
/// Find the correct RectMask2D for a given IClippable.
/// </summary>
/// <param name="clippable">Clippable to search from.</param>
/// <returns>The Correct RectMask2D</returns>
public static RectMask2D GetRectMaskForClippable(IClippable clippable)
{
RectMask2D componentToReturn = null;
return componentToReturn;
}
/// <summary>
/// Helper function to determine if the child is a descendant of father or is father.
/// </summary>
/// <param name="father">The transform to compare against.</param>
/// <param name="child">The starting transform to search up the hierarchy.</param>
/// <returns>Is child equal to father or is a descendant.</returns>
public static bool IsDescendantOrSelf(Transform father, Transform child)
{
if (father == null || child == null)
return false;
if (father == child)
return true;
while (child.parent != null)
{
if (child.parent == father)
return true;
child = child.parent;
}
return false;
}
#endregion
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment