Changing material properties of masked UI

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:

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?

1 Like

Bump

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.

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.

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.

if (m_StencilValue > 0 && !isMaskingGraphic)
{
    var maskMat = StencilMaterial.Add(toUse, (1 << m_StencilValue) - 1, StencilOp.Keep, CompareFunction.Equal, ColorWriteMask.All, (1 << m_StencilValue) - 1, 0);
    StencilMaterial.Remove(m_MaskMaterial);
    m_MaskMaterial = maskMat;
    toUse = m_MaskMaterial;
}

Where StencilMaterial.Add is a very big function that does some relatively heavy operations. I would like to avoid it as much as possible.