I have a Unity Mask trying to mask all their children. The problem is that some of his children need to change their sorting order. To do that I’ve used a Canvas with override sorting. Every children using this kind of Canvas is not masked, but if override sorting is disabled, it is masked.
How can I correctly mask these images while keeping the sorting order that I want?
I have it working now.
Add the child object with a Canvas that overrides sorting.
Add the mask and image you need to that object or child making sure the objects to be masked out are children of it.
In the hierarchy we have a Canvas at the top.
We need to add a child Canvas under that to override the sorting order.
In order for a mask to work correctly in this situation it needs to be a child of this second Canvas in the hierarchy.
What if we want to create a scroll view with RectMask2D, and its children have the Canvas component attached to them? We need the nested Canvas because we want to control the sorting layer of the children, so we have to use the Override Sorting to achieve this. But once enabling the Override Sorting option, the RectMask2D that is under the parent Canvas no longer works, it is not masking the children that have the nested Canvas with Override Sorting enabled.
How do we address this issue?
I recently ran into the same problem. Here is a script I wrote to work around it.
Attach it to the child game object, and set the target to the mask RectTransform game object.
Has this been fixed yet? We have the same issue and it’s holding up a client project significantly. We are also pro users, so we would appreciate if a Unity rep would get on this. Broken mask functionality is very much not expected behavior for a professional development environment.
Also, some more blunt engineer advice: Throw out the UI Canvas system. It’s abysmal. Integrate a new system into the regular 2D world space with the same laws of physics - sprite renderers, sorting orders, etc. – and keep it there.
I have a ScrollRect and some objects under it that override sort order in separate Canvas elements, in order to be able to drag them and render the dragged object over the rest. This had the effect that on the edges of the ScrollRect the Images with overridden sort orders don’t respect the ScrollRect Viewport mask anymore and are rendered outside the ScrollRect. However, the script solves this. Much obliged.
For me the script works even without Update calls. I just call SetTargetClippingRect at start and that’s it. Tried it with dragging around ScrollRect, dragging object inside ScrollRect, scaling and resizing ScrollRect - all seem to work. My mask is RectMask2D (not the default Mask that you’re given). Not sure if there’s any situation where clipping stops working.
Shoutout to @visca_c for the original script, here’s my implementation:
My final working implementation, beyond this I leave it to the community to improve and hopefully for Unity to implement their own solution.
Put this near object you want clipped, remember to reference CanvasRenderer in Editor and have some manager class call Initialize with root (top-most) canvas and rect transform of object that holds mask.
using UnityEngine;
using UnityEngine.EventSystems;
public class MaskedObject : UIBehaviour
{
[SerializeField]
private CanvasRenderer canvasRendererToClip = null;
private Canvas rootCanvas = null;
private RectTransform maskRectTransform = null;
private bool initialized = false;
protected override void OnRectTransformDimensionsChange()
{
base.OnRectTransformDimensionsChange();
if( initialized )
{
SetTargetClippingRect();
}
}
public void Initialize(Canvas rootCanvas, RectTransform maskRectTransform)
{
this.rootCanvas = rootCanvas;
this.maskRectTransform = maskRectTransform;
SetTargetClippingRect();
initialized = true;
}
private void SetTargetClippingRect()
{
Rect rect = maskRectTransform.rect;
// Get local position of maskRect as if it was direct child of root canvas, then offset mask rect by that amount
rect.center += (Vector2)rootCanvas.transform.InverseTransformPoint( maskRectTransform.position );
canvasRendererToClip.EnableRectClipping( rect );
}
}
Yeah, this is still broken. The solution posted here is cumbersome and this should just work out of the box. Unity, is there any update on the status of this? Regardless of sort order, the object is a child of a Rect2DMask, so if it’s outside of the clipping bounds it should be masked. That’s what everyone here expects, and it doesn’t work.
Currently I’ve managed a simple solution for where I need this, by making each object sit on the same level in the hierarchy. So:
[Parent with RectMask2D]
----[Child1]
----[Child2] < – child 2 is drawn above child 1.
---- etc etc.
I’m not sure it’s supposed to work THIS way either, but right now it’s working. By the way I have no canvases on any of these objects. The parent of the rectmask2d object has a Canvas with general sort order set.
I think this was never addressed nor fixed, currently on this same situation, needed a ‘specific’ sorting, in which objects still draw after the masker one yet somehow the stencil value is either not set nor handled. Same with RectMask2D components.
Going to try maybe those hand made ‘EnableClippingRect’ but sounds totally overkill.