Search Unity

TextMesh Pro (Solved) Unable to update material properties at runtime (TextMeshProUGUI)

Discussion in 'UGUI & TextMesh Pro' started by MSplitz-PsychoK, May 18, 2019.

  1. MSplitz-PsychoK

    MSplitz-PsychoK

    Joined:
    May 16, 2015
    Posts:
    1,278
    Hello, my issue is with TextMeshProUGUI, not TextMeshPro.

    Does anyone know how to force TextMeshProUGUI to update it's material or material property values immediately at runtime? (through code)

    Any edits I make to material properties in code will not take effect immediately, and will wait for some other condition (EG. becomes visible, text updates, color changes).

    I've tried:
    - Updating all accessible materials on the TextMeshProUGUI component (.material, .materialForRendering, .fontMaterial, .fontSharedMaterial, .defaultMaterial)
    - Setting the materials to new instances of the materials each frame
    - Calling .SetMaterialDirty() and .SetAllDirty()
    - Calling .ForceMeshUpdate() and .UpdateFontAsset()
    - Getting access to the TMP_SubMeshUI component and trying all of the above on it, plus calling .RefreshMaterial()
    - Getting access to the CanvasRanderer and setting materials to new instances and updating properties each frame

    I can see the material being used at runtime in the inspector's debug mode, labelled "Current Material", but I absolutely cannot find a way to update that material or it's values at runtime without some random delay involved. I can see and edit a few other material values, but that does not help one bit!

    I appreciate any time or help. Just a reminder my issue is with TextMeshProUGUI, not TextMeshPro.
     
  2. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    Are you making these changes when the object is disabled? if so, use ForceMeshUpdate(true); where the object will get update even if the object is disabled.

    Make sure you are not making changes to an instance of the material.

    If you can't solve this, simply provide me with a complete example script that you are using to do this and I'll be able to point out why / what should be changed to make this work.
     
    MSplitz-PsychoK likes this.
  3. MSplitz-PsychoK

    MSplitz-PsychoK

    Joined:
    May 16, 2015
    Posts:
    1,278
    Thanks for your reply. The object is never disabled, and ForceMeshUpdate(true) does not seem to work. I'm aware of the possibility that I may be making edits to the wrong instance of the material, but I'm literally modifying every instance I can find access to, and none of them seem to apply edits immediately.

    Here is my script (Unity 2018.3.9f1):

    Code (CSharp):
    1. public class LetterAutoBlur : MonoBehaviour
    2. {
    3.  
    4.     [SerializeField] TextMeshProUGUI textField;
    5.  
    6.     TMP_SubMeshUI subMesh = null;
    7.     Material textMat = null;
    8.  
    9.     void Start()
    10.     {
    11.         textMat = new Material(textField.fontSharedMaterial);
    12.         textField.fontMaterial = textMat;
    13.  
    14.         subMesh = GetComponentInChildren<TMP_SubMeshUI>();
    15.         if (null != subMesh)
    16.         {
    17.             subMesh.material = textMat;
    18.         }
    19.     }
    20.  
    21.     void Update()
    22.     {
    23.         textField.defaultMaterial.SetFloat("_BlurOffset", Time.time);
    24.         textField.fontMaterial.SetFloat("_BlurOffset", Time.time);
    25.         textField.fontSharedMaterial.SetFloat("_BlurOffset", Time.time);
    26.         textField.material.SetFloat("_BlurOffset", Time.time);
    27.         textField.materialForRendering.SetFloat("_BlurOffset", Time.time);
    28.         textField.SetMaterialDirty();
    29.         textField.SetAllDirty();
    30.  
    31.         if (null != subMesh)
    32.         {
    33.             subMesh.SetMaterialDirty();
    34.             subMesh.SetAllDirty();
    35.         }
    36.  
    37.         textField.ForceMeshUpdate(true);
    38.  
    39.         // Setting the outline color here makes the material update slightly more often
    40.         textField.outlineColor = new Color(Mathf.Sin(Time.time) * 0.5f + 0.5f, 1, 1, 1);
    41.     }
    42.  
    43. }
    44.  
    When I run the game, this is what my text looks like, it does not change unless it is hidden then re-shown.
    C1.PNG

    In Edit Mode, I edit the material, de-activate the GameObject, then re-activate the GameObject, this is what the text looks like.
    C2.PNG

    When I select the GameObject at runtime, I can see the material edit in realtime, but the text in-game will only very occasionally reflect edits to the material.
    C3.PNG
     
  4. MSplitz-PsychoK

    MSplitz-PsychoK

    Joined:
    May 16, 2015
    Posts:
    1,278
    I figured it out a hacky solution that I'm satisfied with for my current project. Thanks again for your time and suggestions.

    Solution:
    You have to create an instance of the material, assign it to the .fontMaterial property, and keep a copy of it. When you wish to edit the material, you must again assign the .fontMaterial property to the instance of the material from earlier, then you can edit the .fontMaterial property of the TextMeshProUGUI object.

    Here is the bare-minimum script:

    Code (CSharp):
    1. public class LetterAutoBlur : MonoBehaviour
    2. {
    3.  
    4.     [SerializeField] TextMeshProUGUI textField;
    5.  
    6.     Material textMat = null;
    7.  
    8.     void Start()
    9.     {
    10.         textMat = new Material(textField.fontSharedMaterial);
    11.         textField.fontMaterial = textMat;
    12.     }
    13.  
    14.     void Update()
    15.     {
    16.         textField.fontMaterial = textMat;
    17.         textField.fontMaterial.SetFloat("_BlurOffset", Time.time);
    18.     }
    19.  
    20. }
     
  5. josefgrunig

    josefgrunig

    Joined:
    Jan 23, 2017
    Posts:
    62
    Similar issue here: after changing a property of the material I need to create a new instance of the modified material otherwise it gets not updated. Are we missing something?

    Code (CSharp):
    1.  
    2. mGlowActionScoreMaterial.SetColor(ShaderUtilities.ID_UnderlayColor, diceColor);
    3. myActionScoreText.fontMaterial = new Material(mGlowActionScoreMaterial);
    4.