Search Unity

Unity UI Masked Material Shader Changes not working correctly

Discussion in 'UGUI & TextMesh Pro' started by Piflik, Mar 13, 2018.

  1. Piflik

    Piflik

    Joined:
    Sep 11, 2011
    Posts:
    293
    I regularly run into the same problem currently:

    I have a Material on an UI-Image that is masked by a parent with a Mask Component. Now I want to change some Material Properties via script (SetTexture, SetFloat, etc). I know that there is a new-ish 'MaterialForRendering' property, especially for masked Materials, but for some reason, Unity is unable to use this properly. When I edit properties before turning the Mask on, they are not applied to the masked material, and vice versa. (When I enable the Mask for the first time, the material is copied correctly, but on all subsequent enable/disables, the materials seem to be handled completely separate.)

    I already filed a bug report weeks ago (994413), but it was closed because apparently it is "its not the common case" to want to enable/disable a Mask after changing material properties during runtime.

    An additional problem is that we create all our UI via code, not buy building it in the Editor, so even if I never enable/disable a Mask, I cannot guarantee that material changes happen always after Unity has copied the Material for masking. I can do the changes after parenting, but the masking/material-copying seems to happen sometime during rendering, so I have to make some changes to the 'material', but later ones to the 'materialForRendering'.

    My current 'workaround' is to never disable/enable masks (which brings some limitations to how my application looks) and duplicate every change manually like so (which is stupid):


    img.material.SetFloat("Name", value);
    img.materialForRendering.SetFloat("Name", value);


    Is there a known fix that actually works, or is my use-case just too outlandish?
     
    Arthur-LVGameDev likes this.
  2. Piflik

    Piflik

    Joined:
    Sep 11, 2011
    Posts:
    293
    I just now found a possible solution.

    I noticed that the masked material will be updated corerctly when I disable the object and enable it again. So I got the UI Repository from Bitbucket and had a look at MaskableGraphic.cs. I copied the following two lines from OnDisable() to RecalculateMasking(), compiled the solution into a dll and replaced the one in my unity installation:

    Code (CSharp):
    1. StencilMaterial.Remove(m_MaskMaterial);
    2. m_MaskMaterial = null;
    I do not know if that produces problems elsewhere, though.
     
  3. Dargon_huihui

    Dargon_huihui

    Joined:
    Mar 23, 2016
    Posts:
    9
    I have the same problem!Are you solved now?
     
  4. Zapan15

    Zapan15

    Joined:
    Apr 11, 2011
    Posts:
    186
    The following code should work:

    Code (CSharp):
    1.             //We have to disable and enable the mask component
    2.             //as we changing the default shader, the
    3.             //mask did not refresh the shader for the masking
    4.             //components.
    5.             //MaskUtilities.Notify2DMaskStateChanged and
    6.             //MaskUtilities.NotifyStencilStateChanged did not work!
    7.             //https://forum.unity.com/threads/masked-ui-elements-shader-not-updating.371542/
    8.             //https://forum.unity.com/threads/masked-material-shader-changes-not-working-correctly.521637/#post-3560220
    9.             //Caution: alloc
    10.             Mask[] masks = GameObject.FindObjectsOfType<Mask>(true);
    11.             if ((masks != null) && (masks.Length > 0)) {
    12.                 for (int i = 0; i < masks.Length; i++) {
    13.                     Mask m = masks[i];
    14.                     bool oldEnabled = m.enabled;
    15.                     m.enabled = false;
    16.                     m.enabled = true;
    17.                     m.enabled = oldEnabled;
    18.                 }
    19.             }
     
    Arthur-LVGameDev likes this.