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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Changing material properties of masked UI

Discussion in 'UGUI & TextMesh Pro' started by tbosmanGP, Feb 21, 2022.

  1. tbosmanGP

    tbosmanGP

    Joined:
    Nov 20, 2019
    Posts:
    4
    I'm having trouble changing material properties for a masked UI image. I am aware a mask will use a modified (new) material for the image and therefor I can't set the properties to the base material. So as I have found, the solution is to use:
    Code (CSharp):
    1. Image.materialForRendering.SetFloat("_Property", 0f);
    However, this method is quite slow since it will grab all affecting components and find this material. In my case, we have a lot of UI components with some shiny effects where the value gets set every update (can be more optimized, I know). So calling materialForRendering on ~50 UI components each update on mobile is not gonna cut it.

    I tried caching the materialForRendering but couldn't find proper callbacks to refresh its cache when the mask layout is changed.

    Any idea on how to do this efficiently? Or a callback for when m_MaskMaterial is changed?
     
  2. tbosmanGP

    tbosmanGP

    Joined:
    Nov 20, 2019
    Posts:
    4
  3. falsevac

    falsevac

    Joined:
    Mar 16, 2016
    Posts:
    33
    Hi, how slow does materialForRendering seem to be for you? I'm using it on hundreds of UI objects and not seeing a performance hit. I couldn't find any documentation on what materialForRendering is actually doing under the hood.
     
  4. tbosmanGP

    tbosmanGP

    Joined:
    Nov 20, 2019
    Posts:
    4
    It will only have an impact when you are using masks on these components. I did a quick test and made a screenshot. This is in the editor so it is not very accurate but it does show what happens.

    upload_2022-4-19_13-18-2.png

    Since we are targeting low-end devices, I am looking for the most efficient approach of doing this.

    Here is the unity code what happens under the hood if you are interested.
    Code (CSharp):
    1. if (m_StencilValue > 0 && !isMaskingGraphic)
    2. {
    3.     var maskMat = StencilMaterial.Add(toUse, (1 << m_StencilValue) - 1, StencilOp.Keep, CompareFunction.Equal, ColorWriteMask.All, (1 << m_StencilValue) - 1, 0);
    4.     StencilMaterial.Remove(m_MaskMaterial);
    5.     m_MaskMaterial = maskMat;
    6.     toUse = m_MaskMaterial;
    7. }
    Where StencilMaterial.Add is a very big function that does some relatively heavy operations. I would like to avoid it as much as possible.