Search Unity

New UI System: anchoring to other objects than parent & masks changing shape and size

Discussion in 'UGUI & TextMesh Pro' started by ugur, Dec 19, 2014.

  1. ugur

    ugur

    Joined:
    Jun 3, 2008
    Posts:
    692
    So thanks to working a lot in the past few months, i'm after trying it in way earlier betas just now getting to play with the new UI system more again.

    And there i wondered if its my lack of experience with it or current shortcomings of the system, but some things i would think should be quite easy to do in a UI system prove unnecessarily difficult or impossible.
    (Though i have to say i like the general system =) )

    So what i'd like to do is just have some elements (sprites, some of which are animated sprites) masked by another rectangular shape. And that mask rectangle should animate to change in dimensions

    (so it should basically unveil the masked elements slowly over time).

    Now in other setups one can set which object a mask should mask, but in unity's new ui system it seems to be the nested child objects and not possible to set it to mask the child objects of some other game object/ ui container (correct me if i'm wrong =) ).

    Then its seems for the anchoring system, the way it works is that elements are anchored to the next higher up/parent object and there's no way to anchor an object (or sides of it) to some other object than the parent container (again: correct me if i'm wrong =) ).

    So then, when let's say i have a panel with a mask on it, it masks the child sprite images nicely, but when i resize the parent (since i want to resize/reposition the mask), then the nested child objects wobble move around there since they are anchored to the panel masking them.

    Did i get this all wrong or is it a shortcoming/deficiency in the current setup that could/would be addressed in the future?

    Basically i

    1) would like to be able to tell a mask to mask some other object and its children instead of the children of the object with the mask script on it

    2) anchor objects or one of their sides to something else than the parent container.

    This in particular is something essential in more complex ui setups, not just in this particular use case.
     
    Circool and ibyte like this.
  2. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    I've forwarded question 1) to the UI team.

    As for 2), it's not something built into the anchoring system (by design, to keep it simpler) but the functionality can be created as a reusable custom script without too much trouble.

    Rune
     
  3. ugur

    ugur

    Joined:
    Jun 3, 2008
    Posts:
    692
    Hello Rune,
    thanks for forwarding 1) to the UI team =)
    Regarding 2) Are there any examples on this somewhere? On that note i also really think you should give the new UI system a name. It's ok if it was decided it should not be UGUI, but yeah, it has to have a name, else it is kinda difficult to find any infos on it specifically on Google etc which are not for some other UI System /version for Unity.
     
  4. phil-Unity

    phil-Unity

    Unity UI Lead Developer

    Joined:
    Nov 23, 2012
    Posts:
    1,226
    So in terms of 1) at the moment it wouldn't be possible to mask other items other than the children items. This is because its hard coded that once it gets out of the child hierarchy it unmasks itself. That being said I can see why you'd want what you suggested but we'd have to come up with a nice solution to make it easy to use. Could you do a feature request through the editors bug reporting system such that it gets on our radar.
     
  5. ugur

    ugur

    Joined:
    Jun 3, 2008
    Posts:
    692
    Hello Phil, thanks for the explanation. Yes, it would really be extremely useful for many things to be able to set other targets for a mask.
    And ok, i submitted a bug report on it now, Case 657831 .
    Maybe it could work the way that when adding a mask component it would have as default value for target the contents/children of the object one adds the mask on but then one could also SetTarget for it in code and on visual inspector side it could by default populate a public target field as the object the mask was added to but then one could just drag another object there to make that and its children the masked one(s).
    Well, i'm sure you'll think of something cool, i just dropped in ideas =)
    thanks again =)
     
  6. phil-Unity

    phil-Unity

    Unity UI Lead Developer

    Joined:
    Nov 23, 2012
    Posts:
    1,226
    Yup thats how i pictured it would work as well, it'd just be making it work nicely on the back end as currently its a very linear pass to generate everything. The other fun thing is making it work with elements not part of its canvas (think nested canvases). it sounds so simple yet its not :(
     
  7. ugur

    ugur

    Joined:
    Jun 3, 2008
    Posts:
    692
    Haha, yeah, i imagine, it's most times like that =) Thanks for your efforts and good luck with it, really appreciate it =)
     
  8. Adrenesis

    Adrenesis

    Joined:
    Feb 22, 2015
    Posts:
    7
    Sorry for necroing, but I got the same problem and this is the most relevant topic about it.

    Here is a quick solution:

    Attach that to the Item you want to lock under your moving mask:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class LockUIItem : MonoBehaviour {
    5.     private Vector3 position;
    6.     // Use this for initialization
    7.     void Awake () {
    8.         position = this.gameObject.GetComponent<RectTransform>().position;
    9.     }
    10.    
    11.     // Update is called once per frame
    12.     void Update () {
    13.         if(position != this.gameObject.GetComponent<RectTransform>().position)
    14.         {
    15.             this.gameObject.GetComponent<RectTransform>().position = position;
    16.         }
    17.     }
    18. }
    19.  
    bye =)
     
    Acoustic125, EgoJacky, mdrunk and 2 others like this.
  9. EgoJacky

    EgoJacky

    Joined:
    Aug 15, 2017
    Posts:
    28
    5 years later and still useful, thank you ;)
     
    Acoustic125 likes this.
  10. notActual_dev

    notActual_dev

    Joined:
    Oct 8, 2019
    Posts:
    2
    Just luv you man <3
     
  11. yoiang

    yoiang

    Joined:
    Jun 3, 2019
    Posts:
    6
    Doubling down on @Adrenesis' lovely hack with more error handling and In-Editor support that def breaks in some fancy corner case:
    https://gist.github.com/yoiang/e5ff2d0f53208859d63efc78521eba01
     
  12. SteenPetersen

    SteenPetersen

    Joined:
    Mar 13, 2016
    Posts:
    104
    7 years later, we still cannot simply animate a mask in the UI. Is this something that will be included ever? This post is still the most relevant, but it offers no real solutions, people are posting workarounds to something that should have been implemented by now.

    @phil-Unity
     
    Last edited: Jun 23, 2021
  13. Hosnkobf

    Hosnkobf

    Joined:
    Aug 23, 2016
    Posts:
    1,096
    Just want to throw in my Asset Better UI which has a very advanced workaround for this problem: Anchor Overrides.
    I explain it in this video:
     
  14. Chri5topheru5

    Chri5topheru5

    Joined:
    Dec 21, 2017
    Posts:
    5
    Any updates on masking other ui elements outside of own children? @phil-Unity
     
  15. Chri5topheru5

    Chri5topheru5

    Joined:
    Dec 21, 2017
    Posts:
    5
    Thx for your code. I updated the snippet to improve performance, as gameObject.GetComponent() is a quite expensive call.

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class LockRectTransform : MonoBehaviour
    4. {
    5.     private RectTransform rectTransform;
    6.     private Vector3 position;
    7.  
    8.     // Use this for initialization
    9.     void Awake()
    10.     {
    11.         rectTransform = gameObject.GetComponent<RectTransform>();
    12.         position = rectTransform.position;
    13.     }
    14.  
    15.     // Update is called once per frame
    16.     void Update()
    17.     {
    18.         if (position != rectTransform.position)
    19.         {
    20.             rectTransform.position = position;
    21.         }
    22.     }
    23. }
     
  16. Josh707

    Josh707

    Joined:
    Jul 12, 2012
    Posts:
    71
    There's another approach to having a mask UI element that masks non-child objects, outside of locking a transform/negating parent transform movement.

    The UI masking uses the stencil buffer under the hood - there's some internal code that automatically determines stencil values for UI materials based on the transform hierarchy and mask components, but the end result is that the built-in default UI shader just uses stencil operations, so you could remove the mask component and set up stenciling yourself. One major upside of this approach is that it doesn't rely on a MonoBehaviour locking/negating object positions and thus it works outside of play mode/is not subject to changing your UI positioning against your will so you're free to do whatever you normally would.

    The gist is the following:
    1. Make 2 materials using the UI/Default shader for mask 'writer' and mask 'reader' UI elements
    2. Pick the same arbitrary stencil value for both materials, and set the mask writer material's stencil settings to pass always & replace - while the mask reader to pass if equal, so that it only draws where the mask writer has drawn.
    3. Assign the mask writer material to the UI element you want to act as the mask, and the mask reader material to elements you want to be masked.
    And then a few things to make note of:
    • TextMeshPro exposes stencil properties in it's debug settings dropdown, so you can set up text elements to perform or be subject to masking as well.
    • UI elements are quads and the stencil buffer value will be written for all pixels on the quad so you'll notice the transparent parts of your UI textures will still mask-in the other elements. If you want the masked elements to respect the transparency of the mask texture you will have to enable alpha clipping on the stencil writer material so that it discards transparent pixels from drawing (and by extension skips writing to the stencil buffer there).
    • If you have overlapping UI elements that mix and match this approach with Unity's mask component, you could theoretically encounter conflicting stencil settings with it's automatically chosen ones and get unexpected results.
     
    Last edited: Mar 7, 2024
    Hosnkobf likes this.