Search Unity

Masked UI Element's Shader Not Updating

Discussion in 'UGUI & TextMesh Pro' started by michaelhill, Dec 3, 2015.

  1. michaelhill

    michaelhill

    Joined:
    Nov 4, 2015
    Posts:
    11
    I have a custom shader I am trying to use on a UI Image element. When the element is rendered by itself, the shader works fine. If I make the UI Image a child of an object with a mask, the shader ceases to update unless I disable and reenable it again.

    I have found this problem also happens with the default UI shader as well.

    I am using Unity 5.2.3f1.

    Here is an example of what's happening:

    The top row of images use my custom shader with an animated value.
    The bottom row is using Unity's default UI shader with an animated color element.

    The left column shows unmasked elements.
    The right column shows the same objects placed inside an element with a mask script on it.

    Using "SetMateralDirty()" or "SetAllDirty()" on any of the masking elements on the right does not change the problem.

    Has anyone encountered this problem before? I've tried looking around but haven't found a solution. I've attached a copy of the project shown above to help anyone who might want to have a peek.

    Cheers and thanks for the help -M
     

    Attached Files:

    Last edited: Dec 3, 2015
  2. CMHooe

    CMHooe

    Joined:
    Oct 27, 2014
    Posts:
    2
    In diagnosing a bug in my project today, I've discovered I'm running into this exact same issue. I'm still on 5.2.2f1 on my end, but I was not experiencing the issue prior to that version (the relevant shader and MonoBehavior in question in my case I originally authored in August, so I'm guessing that's 5.1.x timeframe).

    EDIT: just double-checked, and yep everything works fine if I disable the UI mask component outright. Altering the "Show Mask Graphic" field (enabled in my original implementation) does not resolve the issue, however.
     
    Last edited: Dec 5, 2015
  3. michaelhill

    michaelhill

    Joined:
    Nov 4, 2015
    Posts:
    11
    Did you ever make any progress on this? I'm still stuck. Had to work around it by removing the mask, but that shouldn't be the solution.
     
  4. phil-Unity

    phil-Unity

    Unity UI Lead Developer

    Joined:
    Nov 23, 2012
    Posts:
    1,226
    So guessing here but pretty sure the issue is due to us copying the shader and making modifications to support stencils. My guess is that the material that you are referencing for the animation is not the one that is being used to draw (using the original vs the copied).
     
  5. michaelhill

    michaelhill

    Joined:
    Nov 4, 2015
    Posts:
    11
    So which material would I need to grab in order to do the animation? Would that be the one on the parent with the image mask?
     
  6. michaelhill

    michaelhill

    Joined:
    Nov 4, 2015
    Posts:
    11
    Okay, so it looks like Phil is correct. The reference is being broken in some way that I'm not very clear on. I did some poking around and found the SetGlobalFloat(string propertyName, float value).

    By making the animated value in my shader private, I can then animate it as follows:
    Code (CSharp):
    1. Shader.SetGlobalFloat("_FadeIntensity", lerpValue);
    I only have one object on screen that needs to be animated, so this solution works for me, but it's certainly not a workable solution of you need independent animations for multiple objects on screen.
     
    MUGIK and __blend like this.
  7. __blend

    __blend

    Joined:
    Apr 8, 2016
    Posts:
    1
    This is really a problem that has to be resolved. Thanks michaelhill for the fast solution.
     
  8. dpolyakov

    dpolyakov

    Joined:
    Dec 18, 2015
    Posts:
    16
    I got the same exact problem (not updating parameters in shader), but I instantiate a material as:

    Code (CSharp):
    1. Image img = GetComponent<Image>();
    2. m_mat = Instantiate(img.material);
    3. img.material = m_mat;
    4.  
    So this solution is not going to work as it will change parameters globally.
    Inside my c# code I call:
    m_mat.SetColor("_Color", m_color);

    Any ideas how to pass parameters to a shader with a stencil?
     
  9. nxtboyIII

    nxtboyIII

    Joined:
    Jun 4, 2015
    Posts:
    281
    I'm experiencing the same issue...
     
  10. nxtboyIII

    nxtboyIII

    Joined:
    Jun 4, 2015
    Posts:
    281
    It looks like a work around is by disabling the image, then re-enabling it right after
     
    KevIU likes this.
  11. cschmidtHT

    cschmidtHT

    Joined:
    Aug 31, 2016
    Posts:
    3
    Phil-Unity had it right but didn't elaborate enough to keep you from just hacking around with the global parameters.

    The Mask object causes a modified material to be rendered rather than the baseMaterial so it is no longer rendering the texture that you are updating with the "material" property. Using set on the materialForRendering property will set the correct material if a mask is involved.

    So in your project adding

    topImageMasked.materialForRendering.SetFloat("_FadeIntensity", lerpValue);
    bottomImageMasked.materialForRendering.color = newColor;
     
    Beennn, Oxygeniium, TEEBQNE and 3 others like this.
  12. sandbok

    sandbok

    Joined:
    Dec 1, 2016
    Posts:
    19
    Thank you so much! This had been giving me a lot of trouble, but using "materialForRendering" fixes my problem.
     
  13. Piflik

    Piflik

    Joined:
    Sep 11, 2011
    Posts:
    293
    I have encountered the problem now as well. But .materialForRendering does not work in my case, since I need to change the properties while the mask is disabled and enable the mask later. Use .material or .materialForRendering does not make a difference, since .materialForRendering points to two different materials, the original and the stenciled copy, depending on the state the mask is in, and the copy is not updated when the original is edited.

    I filed a bug-report (case 994413) in the hopes that this behaviour might be fixed in a future release.
     
    Last edited: Jan 29, 2018
  14. 334499p

    334499p

    Joined:
    Nov 2, 2014
    Posts:
    1
    Incase anyone's looking for a solution- After setting the material's property, simply disable and enable the graphic component in two lines : img.enabled = false; and then img.enabled = true;
     
  15. cronus98

    cronus98

    Joined:
    Jul 5, 2017
    Posts:
    3
    I can't believe this is the correct solution, but it absolutely worked for me. Is there no better way?

    I guess it also begs the question, does disable/enable have any overhead?
     
    Misha_Kh likes this.
  16. Piflik

    Piflik

    Joined:
    Sep 11, 2011
    Posts:
    293
    I have a 'solution', but I don't know if it is better. I dug a bit in Unity's open source CS Reference and made a small edit to MaskableGraphic.cs and built a custom dll. Sadly you cannot replace Unity Engine dlls in your Project, you have to replace them in the installation Folder.
     
  17. BelieveXiaoShuai

    BelieveXiaoShuai

    Joined:
    Nov 6, 2017
    Posts:
    21
    It does not work in Unity 2019.2.1f1
     
  18. ArcticPinou

    ArcticPinou

    Joined:
    Dec 24, 2015
    Posts:
    11
    Thanks for this thread.
    In my project, I had the same issue, a material with a custom shader not updating when changing the value through code. After updating the value, I found that disabling / enabling the gameobject worked, but I also found this line of code that looks more elegant imo:
    Code (CSharp):
    1. MaskUtilities.NotifyStencilStateChanged(_maskReference);
     
  19. JonPQ

    JonPQ

    Joined:
    Aug 10, 2016
    Posts:
    120
    known unity bug.
    https://issuetracker.unity3d.com/is...ated-when-setting-via-shader-dot-setglobalint

    I have the same problem. Adding stencil support to a simple shader, results in the material not being editable in the inspector window... all the shader variables/properties become greyed out in inspector, and non-interactable.
    The shader works just fine, but you have to edit the material separately, not on the game-object it is assigned to.
     
  20. firstuser

    firstuser

    Joined:
    May 5, 2016
    Posts:
    147
    Yeah I had to force a UI refresh to get it working, and even then sometimes there is a flicker, etc.