Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Ability to mask several UI elements at once is a sorely missing feature

Discussion in 'UGUI & TextMesh Pro' started by cj-currie, Aug 28, 2021.

  1. cj-currie

    cj-currie

    Joined:
    Nov 27, 2008
    Posts:
    301
    I've been trying to make a mask that scales and translates to reveal my UI when a player enters the scene. I'm discovering the severe limitations of the UI Masking system which all boil down to one simple problem:
    • Masking is determined by hierarchy
    This means that attempting to scale or translate a mask messes with all the elements that *must* be under the mask in order to work. The common workaround I've seen is to
    1. unparent child elements
    2. transform mask
    3. reparent child elements
    However this does not work right when contained within the same function. Strange bugs occur where child transforms get set to 0 or otherwise disappear, indicating some kind of mask rendering error. In order to get the mask to update properly, child position/scale values have to be changed during LateUpdate, which means having code logic in two different places (inelegant, hard to maintain, difficult to run multiple instances).

    Worse, there are even more strange bugs where changes made during Play persist after stopping, messing up my entire UI setup. Overall, new UI feels like a giant clustercluck. This is my first project using it and I constantly wish I'd gone with old IMGUI from the beginning.

    I'm on the latest version of Unity.

    I can think of a few ways to fix masking and make it usable:
    • Have masked elements be an array property of the mask, freeing the transform correlation between parent/child that is messing everything up
    • Have a FreeTransform method that will change a parent's transform while leaving child values untouched (relative to world)
    • Enable some kind of LateTransform that forces a transform's logic to happen during LateUpdate, or otherwise after the normal transform logic. This would enable de-parent+transform+reparent to work consistently without strange bugs.
    The second two options would alter fundamental transform logic so I'm thinking the first is more likely. Unity Technologies, please hear my plea!
     
  2. cj-currie

    cj-currie

    Joined:
    Nov 27, 2008
    Posts:
    301
    Also masking apparently doesn't work at all with Outline components. See this ScrollView.

    Edit: It appears that Masking doesn't work with Text components that have a Material assigned (font material), and Outline components *only* work when the Text has Material assigned.

    Edit 2: After some shader experimentation I found that combining the font shader and the default shader resulted in something that allows text to mask while using a font material. Here's the source:

    Code (CSharp):
    1. Shader "Custom/Stencil Text" {
    2.     Properties {
    3.         _MainTex ("Font Texture", 2D) = "white" {}
    4.         _Color ("Text Color", Color) = (1,1,1,1)
    5.  
    6.         _StencilComp ("Stencil Comparison", Float) = 8
    7.         _Stencil ("Stencil ID", Float) = 0
    8.         _StencilOp ("Stencil Operation", Float) = 0
    9.         _StencilWriteMask ("Stencil Write Mask", Float) = 255
    10.         _StencilReadMask ("Stencil Read Mask", Float) = 255
    11.  
    12.         _ColorMask ("Color Mask", Float) = 15
    13.     }
    14.  
    15.     SubShader {
    16.  
    17.         Tags {
    18.             "Queue"="Transparent"
    19.             "IgnoreProjector"="True"
    20.             "RenderType"="Transparent"
    21.             "PreviewType"="Plane"
    22.         }
    23.         Stencil
    24.         {
    25.             Ref [_Stencil]
    26.             Comp [_StencilComp]
    27.             Pass [_StencilOp]
    28.             ReadMask [_StencilReadMask]
    29.             WriteMask [_StencilWriteMask]
    30.         }
    31.  
    32.         Lighting Off Cull Off ZTest Always ZWrite Off
    33.         Blend SrcAlpha OneMinusSrcAlpha
    34.         ColorMask [_ColorMask]
    35.  
    36.         Pass {
    37.             CGPROGRAM
    38.             #pragma vertex vert
    39.             #pragma fragment frag
    40.             #pragma multi_compile _ UNITY_SINGLE_PASS_STEREO STEREO_INSTANCING_ON STEREO_MULTIVIEW_ON
    41.             #include "UnityCG.cginc"
    42.  
    43.             struct appdata_t {
    44.                 float4 vertex : POSITION;
    45.                 fixed4 color : COLOR;
    46.                 float2 texcoord : TEXCOORD0;
    47.                 UNITY_VERTEX_INPUT_INSTANCE_ID
    48.             };
    49.  
    50.             struct v2f {
    51.                 float4 vertex : SV_POSITION;
    52.                 fixed4 color : COLOR;
    53.                 float2 texcoord : TEXCOORD0;
    54.                 UNITY_VERTEX_OUTPUT_STEREO
    55.             };
    56.  
    57.             sampler2D _MainTex;
    58.             uniform float4 _MainTex_ST;
    59.             uniform fixed4 _Color;
    60.  
    61.             v2f vert (appdata_t v)
    62.             {
    63.                 v2f o;
    64.                 UNITY_SETUP_INSTANCE_ID(v);
    65.                 UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
    66.                 o.vertex = UnityObjectToClipPos(v.vertex);
    67.                 o.color = v.color * _Color;
    68.                 o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex);
    69.                 return o;
    70.             }
    71.  
    72.             fixed4 frag (v2f i) : SV_Target
    73.             {
    74.                 fixed4 col = i.color;
    75.                 col.a *= tex2D(_MainTex, i.texcoord).a;
    76.                 return col;
    77.             }
    78.             ENDCG
    79.         }
    80.     }
    81. }
     

    Attached Files:

    Last edited: Aug 28, 2021