Search Unity

TextMesh Pro Underlay not applying in code-loaded material

Discussion in 'UGUI & TextMesh Pro' started by carcasanchez, Jun 18, 2019.

  1. carcasanchez

    carcasanchez

    Joined:
    Jul 15, 2018
    Posts:
    177
    Hello.
    I am working on a localization system, where I load different Font Assets from an asset bundle.
    After loading a font asset, I apply it to any text mesh component it should be, and I configurate the material through C# (applying shading, styles and so on).
    Everything works fine: font is loaded and applied and text is perfectly readable.
    However, material properties like Underlay are not working properly. Despite the UGUI showing the changes I made (and, apparently, the script doing its work assigning values), the text doesn't reflect any changes (besides, weirdly, Outline, wich works fine).
    If I configurate the material from editor, and then start, there is not problem. But if, after that, I execute the localization (loading the new font and the material from the bundle), the material seems to get bugged: any changes I do, no matter if its in the editor or through code, reflect on the text (besides, again, Outline options).
    To be clear: I am assigning the loaded Font asset to the Text Mesh component, and then modifying the fontMaterial (since I only want to change that instance).
    Maybe I am misunderstanding material instancing or I am missing how Text Mesh Pro works internally.
     
  2. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    Properties like Outline and Underlay are enabled by using a ShaderKeyword which might be disabled on the Material you are assigning to these text objects.

    Code (csharp):
    1.  
    2. someMaterial.EnableKeyword("UNDERLAY_ON");
    3.  
    If you take a look / select the shaders themselves, you will be able to see what keywords they use.
     
  3. carcasanchez

    carcasanchez

    Joined:
    Jul 15, 2018
    Posts:
    177
    Yes, I use it!
    The strange thing (no pun intended) about this issue is that it works perfect with pre-loaded materials.
    The moment I create a new material from an asset bundle, it fails.

    This is the code I use to load a new font asset from a bundle:

    Code (CSharp):
    1.  TMP_FontAsset[] fonts = loadedAssetBundle.LoadAllAssets<TMP_FontAsset>();
    2.  
    3.             if (fonts.Length > 1)
    4.             {
    5.                 Debug.LogWarning("WARNING: more than one font in " + language + " asset bundle. Loading first font.");
    6.             }
    7.             else if (fonts.Length == 0)
    8.             {
    9.                 Debug.LogWarning("WARNING: no fonts " + language + " asset bundle.");
    10.                 return;
    11.             }
    12.  
    13.             text.font = actualFont = fonts[0];
    And this Is what I use to set the materials (outlineSettings and underlaySettings are my own config structs):
    Code (CSharp):
    1.    
    2. textInstance = GetComponent<TextMeshProUGUI>();
    3.         materialInstance = textInstance.fontMaterial;
    4.  
    5.   //Outline (this works perfectly)
    6.         if (outlineSettings.outlineActive)
    7.         {
    8.             materialInstance.SetColor("_OutlineColor", outlineSettings.color);
    9.             materialInstance.SetFloat("_OutlineWidth", outlineSettings.thickness);
    10.         }
    11.         else
    12.         {
    13.             materialInstance.SetColor("_OutlineColor", outlineSettings.color);
    14.             materialInstance.SetFloat("_OutlineWidth", 0);
    15.         }
    16.              
    17.         //Underlay (this doesn't work)
    18.         if (underlaySettings.underlayActive)
    19.         {
    20.             materialInstance.EnableKeyword(ShaderUtilities.Keyword_Underlay);
    21.  
    22.             materialInstance.SetColor("_UnderlayColor", underlaySettings.color);
    23.             materialInstance.SetFloat("_UnderlayOffsetX", underlaySettings.offsetX);
    24.             materialInstance.SetFloat("_UnderlayOffsetY", underlaySettings.offsetY);
    25.             materialInstance.SetFloat("_UnderlayDilate", underlaySettings.dilate);
    26.             materialInstance.SetFloat("_UnderlaySoftness", underlaySettings.softness);
    27.         }
    28.         else
    29.             materialInstance.DisableKeyword(ShaderUtilities.Keyword_Underlay);
    30.  
    31.         textInstance.fontStyle = FontStyles.Normal;
    32.  
    33.         if (bold)
    34.             textInstance.fontStyle |= FontStyles.Bold;
    35.         if (italic)
    36.             textInstance.fontStyle |= FontStyles.Italic;
    37.  
    38.         textInstance.UpdateMeshPadding();
    I suspect there is some problem in loading a font asset this way (probably a missing reference or similar).
     
    Vziuh likes this.
  4. carcasanchez

    carcasanchez

    Joined:
    Jul 15, 2018
    Posts:
    177
    Okey, I think I solved it.

    It seems like Text Mesh Pro still misses shader references if you load the font from an asset bundle.
    All I had to do was to add the following line:
    Code (CSharp):
    1.             text.fontMaterial.shader = Shader.Find(text.fontMaterial.shader.name);
    2.  
    Interestingly, if I add the line textInstance.UpdateFontAsset(), the issue still happens. I have also have to remove this line.
     
    zhuofengCai likes this.
  5. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    This is an issue specific to AssetBundles where depending on how the bundles are setup which can result in the Atlas Texture being duplicated or the shaders which results in TMP thinking you are trying to assign a material / texture that doesn't match the one from the font asset. At which point TMP switches back to the default material used in the font asset.