Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

TextMesh Pro Font.CreateDynamicFontFromOSFont not working

Discussion in 'UGUI & TextMesh Pro' started by Father_F1kus, Mar 15, 2022.

  1. Father_F1kus

    Father_F1kus

    Joined:
    Feb 22, 2015
    Posts:
    5
    Greets,

    I downloaded the latest available preview version of TMP (3.2.0-pre.3) to try out the OSFont functionality however i could not get it to work. I followed the yt video as well for general reference:
    and multiple threads but could not get good results. Trying to create a font from code like:
    Code (CSharp):
    1.  
    2. var pingFang = Font.CreateDynamicFontFromOSFont("PingFang SC", 11);
    3. var defaultAsset = translationsConfig.DefaultFontAsset;
    4. var pointSize = defaultAsset.faceInfo.pointSize;
    5. var fontAsset = TMP_FontAsset.CreateFontAsset(pingFang, pointSize, defaultAsset.atlasPadding, GlyphRenderMode.SDFAA, defaultAsset.atlasWidth, defaultAsset.atlasHeight);
    6. defaultAsset.fallbackFontAssetTable.Add(fontAsset);
    7.  
    **** For font names i tried names from: Font.GetOSInstalledFontName, Font.GetPathsToOSFonts, FontEngine.GetSystemFontNames and none of them worked, while using:
    Code (CSharp):
    1.  
    2. var font = new Font(fontPath); // font path comes from Font.GetPathsToOSFonts();
    3. var defaultAsset = translationsConfig.DefaultFontAsset;
    4. var pointSize = defaultAsset.faceInfo.pointSize;
    5. var fontAsset = TMP_FontAsset.CreateFontAsset(font, pointSize, defaultAsset.atlasPadding, GlyphRenderMode.SDFAA, defaultAsset.atlasWidth, defaultAsset.atlasHeight);
    6.  
    Worked, HOWEVER it caused a massive memory overhead due to HUGE font families on IOS.

    I have also tried using the Dynamic OS in the editor for NotoSans family (as per the video):
    upload_2022-3-15_13-3-11.png
    however that did not work as well. ( Could this come down to me using just the otf instead of ttc?)

    Building an "empty" unity project (android APK) with no stripping and a simple scene with fonts set do Dynamic OS and one with just Dynamic, the build size difference is huge. upload_2022-3-15_13-2-54.png

    Am I missing something obvious with DynamicOS? and if there are any workarounds / solutions that you came to on your project please share :)
     
  2. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    For creating font assets at runtime, it is recommended to use the newer API's introduced in the latest preview releases and to create these font assets using a path to the source font file instead of creating a font object first. Creating a font object first increases the memory overhead (as you have uncovered) as the font file ends up being loaded in memory whereas creating from file path will not. Here is an example

    Code (csharp):
    1.  
    2. // Get path to system fonts.
    3. string[] systemFonts = Font.GetPathsToOSFonts();
    4.  
    5. // Create new font asset from one of those paths.
    6. TMP_FontAsset fontAsset = TMP_FontAsset.CreateFontAsset(systemFonts[186], 0, 90, 9, GlyphRenderMode.SDFAA, 1024, 1024);
    7.  
    8. // Assign new font asset to text component.
    9. TextComponent.font = fontAsset;
    10.  
    Here is the summary of that new function above.
    Code (csharp):
    1.  
    2. /// <summary>
    3. /// Creates a new font asset instance from the font file at the given file path.
    4. /// </summary>
    5. /// <param name="fontFilePath">The file path of the font file.</param>
    6. /// <param name="faceIndex">The index of font face.</param>
    7. /// <param name="samplingPointSize">The sampling point size.</param>
    8. /// <param name="atlasPadding">The padding between individual glyphs in the font atlas texture.</param>
    9. /// <param name="renderMode">The atlas render mode.</param>
    10. /// <param name="atlasWidth">The atlas texture width.</param>
    11. /// <param name="atlasHeight">The atlas texture height.</param>
    12. /// <returns>An instance of the newly created font asset.</returns>
    13. public static TMP_FontAsset CreateFontAsset(string fontFilePath, int faceIndex, int samplingPointSize, int atlasPadding, GlyphRenderMode renderMode, int atlasWidth, int atlasHeight)
    14.  

    Alternatively, you can also use the following new API to create the font asset provided you know the Family and Style name of the system font file.

    Code (csharp):
    1.  
    2. // Create new font asset using font Family Name and Style Name.
    3. TMP_FontAsset fontAsset = TMP_FontAsset.CreateFontAsset("Avenir Next", "Heavy", 90);
    4.  
    5. // Assign new font asset to text component
    6. TextComponent.font = fontAsset;
    7.  
    The following new API can also be used to get a list of the system fonts' family and style names.

    Code (csharp):
    1.  
    2. // Use the following API to get a list of the available system fonts
    3. string[] SystemFontNames = FontEngine.GetSystemFontNames();
    4.  

    When using Dynamic OS font assets, you must import the source font file in the Editor and create a font asset just like you normally do with Dynamic font assets. Be sure to change the Atlas Population Mode to Dynamic OS.

    For testing purposes, create a simple scene with a text object that references this dynamic OS font asset. Then create a build to test it all.

    Unlike Dynamic font assets, the source font file will not be included in the build. Instead when the app is launched we will search thru the system fonts for a font file with the same Family Name and Style name. Assuming this font file exists on the target platform, we will use it.

    In order for this to work, the source font file must exist on the target platform. For instance, NotoSans-Regular is not present on iOS. See list of default installed fonts here.
     
  3. Father_F1kus

    Father_F1kus

    Joined:
    Feb 22, 2015
    Posts:
    5
    Hey Stephan, thank your for your reply!
    I tried with:
    Code (CSharp):
    1.  
    2. public static TMP_FontAsset CreateFontAsset(string fontFilePath, int faceIndex, int samplingPointSize, int atlasPadding, GlyphRenderMode renderMode, int atlasWidth, int atlasHeight);
    3.  
    and it worked like a charm. Just need to check it out also on iOS.
    Thank again!
     
  4. Father_Fikus

    Father_Fikus

    Joined:
    May 19, 2021
    Posts:
    5
    @Stephan_B Hey, as a follow up question - i see that faceInfo is no longer accessible to be changed in code. Are there plans to expose the fields - more specifically ascent line? I am also getting a crash:
    Code (CSharp):
    1.  
    2. aused by: com.outfit7.funnetworks.exceptions.EngineException: NullReferenceException: Object reference not set to an instance of an object.
    3. at TMPro.TMP_SubMeshUI.UpdateMaterial .()(Unknown Source)
    4. at
    5. TMPro.TMP_SubMeshUI.SetMaterialDirty .()(Unknown Source)
    6. at
    7. UnityEngine.UI.MaskableGraphic.OnDisable .()(Unknown Source)
    8. at
    9. TMPro.TMP_SubMeshUI.OnDisable .()(Unknown Source)
    10.  
    and:

    Code (CSharp):
    1. NullReferenceException: Object reference not set to an instance of an object
    2. TMPro.TMP_FontAsset.SetupNewAtlasTexture () (at Library/PackageCache/com.unity.textmeshpro@3.2.0-pre.3/Scripts/Runtime/TMP_FontAsset.cs:2859)
    3. TMPro.TMP_FontAsset.TryAddCharacterInternal (System.UInt32 unicode, TMPro.TMP_Character& character) (at Library/PackageCache/com.unity.textmeshpro@3.2.0-pre.3/Scripts/Runtime/TMP_FontAsset.cs:2566)
    4. TMPro.TMP_FontAssetUtilities.GetCharacterFromFontAsset_Internal (System.UInt32 unicode, TMPro.TMP_FontAsset sourceFontAsset, System.Boolean includeFallbacks, TMPro.FontStyles fontStyle, TMPro.FontWeight fontWeight, System.Boolean& isAlternativeTypeface) (at Library/PackageCache/com.unity.textmeshpro@3.2.0-pre.3/Scripts/Runtime/TMP_FontAssetUtilities.cs:169)
    5. TMPro.TMP_FontAssetUtilities.GetCharacterFromFontAssets (System.UInt32 unicode, TMPro.TMP_FontAsset sourceFontAsset, System.Collections.Generic.List`1[T] fontAssets, System.Boolean includeFallbacks, TMPro.FontStyles fontStyle, TMPro.FontWeight fontWeight, System.Boolean& isAlternativeTypeface) (at Library/PackageCache/com.unity.textmeshpro@3.2.0-pre.3/Scripts/Runtime/TMP_FontAssetUtilities.cs:251)
    6. TMPro.TMP_Text.GetTextElement (System.UInt32 unicode, TMPro.TMP_FontAsset fontAsset, TMPro.FontStyles fontStyle, TMPro.FontWeight fontWeight, System.Boolean& isUsingAlternativeTypeface) (at Library/PackageCache/com.unity.textmeshpro@3.2.0-pre.3/Scripts/Runtime/TMP_Text.cs:6097)
    7. TMPro.TextMeshProUGUI.SetArraySizes (TMPro.TMP_Text+TextProcessingElement[] textProcessingArray) (at Library/PackageCache/com.unity.textmeshpro@3.2.0-pre.3/Scripts/Runtime/TMPro_UGUI_Private.cs:1195)
    8. TMPro.TMP_Text.ParseInputText () (at Library/PackageCache/com.unity.textmeshpro@3.2.0-pre.3/Scripts/Runtime/TMP_Text.cs:1965)
    9. TMPro.TextMeshProUGUI.OnPreRenderCanvas () (at Library/PackageCache/com.unity.textmeshpro@3.2.0-pre.3/Scripts/Runtime/TMPro_UGUI_Private.cs:1711)
    10. TMPro.TextMeshProUGUI.Rebuild (UnityEngine.UI.CanvasUpdate update) (at Library/PackageCache/com.unity.textmeshpro@3.2.0-pre.3/Scripts/Runtime/TextMeshProUGUI.cs:216)
    11. UnityEngine.UI.CanvasUpdateRegistry.PerformUpdate () (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/CanvasUpdateRegistry.cs:215)
    12. UnityEngine.Canvas:SendWillRenderCanvases() (at /Users/bokken/buildslave/unity/build/Modules/UI/ScriptBindings/UICanvas.bindings.cs:84)
    13.  
    *** The second one happens always when i try to add new gylphs and the TMP tries to create a new atlas. I checked a thread:
    https://forum.unity.com/threads/chi...t-when-using-fallback-font-in-editor.1123444/
    and it looks like it was implemented, so I had to find a diferent solution and I managed to "bypass" the second crash by calling
    ClearFontAssetData(); however this is more of a hack than a proper solution :(
     
    Last edited: Mar 17, 2022
  5. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    Any reason you are trying to modify the FaceInfo at runtime instead of just editing those values in the Editor which would be the advantage of using Dynamic OS font assets instead of trying to create those font assets at runtime and then having to edit those metrics?
     
    Last edited: Mar 17, 2022
  6. Father_Fikus

    Father_Fikus

    Joined:
    May 19, 2021
    Posts:
    5
    Leftover from previous TMP version where i had custom logic for "normalising" face infos between diferrent fonts. Will update to use SystemOS and check.
    Thanks!
     
  7. AdionN

    AdionN

    Joined:
    Nov 6, 2019
    Posts:
    16
    Code (CSharp):
    1.  
    2. string[] systemFonts = Font.GetPathsToOSFonts();
    3. string[] SystemFontNames = FontEngine.GetSystemFontNames();
    Returns emty lists on WebGL. Any tips how can I find fall back fonts on WebGL build? Tried using DynamicOS mode with NotoSansJP-Regular and MS Gothic On windows fallback works without problems, but on browsers I got nothing at all. Problem is Japanese Kanji. And I cannot build asset with all Kanji, as size would be just too big.

    I assume it is possible, because legacy font is able to fall back to missing characters without a problems...

    Any help would be helpfull.
     
  8. Racines

    Racines

    Joined:
    Jan 20, 2014
    Posts:
    35
    Did yo find a solution for this ?
     
  9. Racines

    Racines

    Joined:
    Jan 20, 2014
    Posts:
    35
    @Stephan_B is it planned to make the SystemOS mode working on WebGL build?
     
  10. jonathan_lumos

    jonathan_lumos

    Joined:
    Jan 20, 2022
    Posts:
    3
    @Stephan_B is it planned to state what platforms are supported for Dynamic OS Fonts?