Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Shader array property causing weirdness with UI masks

Discussion in 'Shaders' started by ProtoTerminator, Dec 25, 2019.

  1. ProtoTerminator

    ProtoTerminator

    Joined:
    Nov 19, 2013
    Posts:
    583
    I have a shader that is fed an array of colors from script, and everything worked great until I had masks on 2 overlapping canvases. The mask in the behind canvas causes the masked image in the front canvas to show if they overlap. After much hair-pulling, I finally narrowed down the issue to array access, which still makes no sense to me. Is there any solution to this?

    Here is the stripped shader code that still exerts this behavior:

    Code (CSharp):
    1. Shader "Custom/Color Shift"
    2. {
    3.     Properties
    4.     {
    5.         [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
    6.  
    7.         _StencilComp ("Stencil Comparison", Float) = 8
    8.         _Stencil ("Stencil ID", Float) = 0
    9.         _StencilOp ("Stencil Operation", Float) = 0
    10.         _StencilWriteMask ("Stencil Write Mask", Float) = 255
    11.         _StencilReadMask ("Stencil Read Mask", Float) = 255
    12.         _ColorMask ("Color Mask", Float) = 15
    13.         [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
    14.     }
    15.     SubShader
    16.     {
    17.         Tags
    18.         {
    19.             "Queue"="Transparent"
    20.             "IgnoreProjector"="True"
    21.             "RenderType"="Transparent"
    22.             "PreviewType"="Plane"
    23.             "CanUseSpriteAtlas"="True"
    24.         }
    25.    
    26.         Stencil
    27.         {
    28.             Ref [_Stencil]
    29.             Comp [_StencilComp]
    30.             Pass [_StencilOp]
    31.             ReadMask [_StencilReadMask]
    32.             WriteMask [_StencilWriteMask]
    33.         }
    34.         Cull Off
    35.         Lighting Off
    36.         ZWrite Off
    37.         ZTest [unity_GUIZTestMode]
    38.         Blend SrcAlpha OneMinusSrcAlpha
    39.         ColorMask [_ColorMask]
    40.         Pass
    41.         {
    42.             Name "Default"
    43.         CGPROGRAM
    44.             #pragma vertex vert
    45.             #pragma fragment frag
    46.             #pragma target 2.0
    47.             #include "UnityCG.cginc"
    48.             #include "UnityUI.cginc"
    49.             #pragma multi_compile __ UNITY_UI_ALPHACLIP
    50.        
    51.             struct appdata_t
    52.             {
    53.                 float4 vertex   : POSITION;
    54.                 float4 color    : COLOR;
    55.                 float2 texcoord : TEXCOORD0;
    56.             };
    57.             struct v2f
    58.             {
    59.                 float4 vertex   : SV_POSITION;
    60.                 fixed4 color    : COLOR;
    61.                 float2 texcoord  : TEXCOORD0;
    62.                 float4 worldPosition : TEXCOORD1;
    63.             };
    64.        
    65.             fixed4 _TextureSampleAdd;
    66.             float4 _ClipRect;
    67.             float _Stencil;
    68.             v2f vert(appdata_t IN)
    69.             {
    70.                 v2f OUT;
    71.                 OUT.worldPosition = IN.vertex;
    72.                 OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
    73.                 OUT.texcoord = IN.texcoord;
    74.            
    75.                 OUT.color = IN.color;
    76.                 return OUT;
    77.             }
    78.             sampler2D _MainTex;
    79.  
    80.             fixed4 _Colors[16];
    81.             int _ColorCount; // Min 1 max 16
    82.             fixed4 frag(v2f IN) : SV_Target
    83.             {
    84.                 fixed4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
    85.                
    86.                 color *= _Colors[0]; // Removing this works as expected.
    87.                
    88.                 color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
    89.                 clip (color.a - 0.001);
    90.                 return color;
    91.             }
    92.         ENDCG
    93.         }
    94.     }
    95. }
    Screen Shot 2019-12-24 at 9.23.55 PM.png
     
  2. ProtoTerminator

    ProtoTerminator

    Joined:
    Nov 19, 2013
    Posts:
    583
    Well, I still have no idea why this works this way, but I managed to hack around it by passing my data in a texture instead of an array, and then adding that texture into the shader's Properties section (seems properties have to be in that section to work with masks, and we can't put arrays in there).
    Then, for some reason, I still had to add this to my script when I update the material, even though I'm setting both
    graphic.material
    and
    graphic.materialForRendering
    ...


    Code (CSharp):
    1. Mask mask = GetComponent<Mask>();
    2. if (mask)
    3. {
    4.     // This is necessary for masking to work properly, for some reason...
    5.     mask.enabled = false;
    6.     mask.enabled = true;
    7. }