Search Unity

Unity 4.6 Bitmap font?

Discussion in 'Unity UI & TextMesh Pro' started by patoffspyder, Aug 28, 2014.

  1. patoffspyder

    patoffspyder

    Joined:
    Jan 22, 2014
    Posts:
    6
    Hi,
    Is it possible to use Bitmap font with the new UGUI system? I am used to NGUI and the artists I work with are always using bitmap fonts for our games, but I can't find a way to use a bitmap fonts with the new UGUI system, only dynamic fonts.
    Thanks.
     
    drHogan likes this.
  2. Stephan-B

    Stephan-B

    Unity Technologies

    Joined:
    Feb 23, 2011
    Posts:
    2,269
    I just tried switch the font from dynamic to ascii set for instance and was surprised to discover that the new UI system requires the font to be set to dynamic.

    P.S. If you are looking for a solution that works with the new UI system as well as bitmap fonts or something even better, take a look at my signature. I tried to PM you but you have that turned off.
     
  3. Tim-C

    Tim-C

    Unity Technologies

    Joined:
    Feb 6, 2010
    Posts:
    2,087
    Well it doesn't require the font to be set to dynamic, it requires that you set up your Text element to respect that it is NOT a dynamic font (use default font size, default styling). Bitmap fonts work when this is configured.
     
  4. sheng319

    sheng319

    Joined:
    Jun 23, 2014
    Posts:
    34
    I have font.png and font.fnt. How to import in Unity, and set to Text font?
     

    Attached Files:

    • font.zip
      File size:
      80.3 KB
      Views:
      503
  5. rakkarage

    rakkarage

    Joined:
    Feb 3, 2014
    Posts:
    679
  6. dhaynes89

    dhaynes89

    Joined:
    Mar 14, 2014
    Posts:
    3
    Tim - can you elaborate on this?

    My team and I are trying to implement bitmap fonts exported from GlyphDesigner.
     
  7. Nikola-B

    Nikola-B

    Joined:
    Jan 31, 2014
    Posts:
    42
    Since you are not planning on using Dynamic fonts, I suggest you take a look at Text Mesh Pro. There is an early beta available from the author that works with Unity 4.6 and when it comes to text, it is an amazing solution with improved text rendering and so much more flexibility over bitmap fonts with no performance impact. Adding a Stroke, Shadow, Bevel, Glow, etc comes down to simply changing material properties.

    Here is a link to the asset store thread where you can see lots of examples and information about it or take a look at the video below.

     
  8. Xylph

    Xylph

    Joined:
    Dec 11, 2013
    Posts:
    29
    EDIT: Is there a way to automate (using Editor) custom font settings using the .fnt file and the font atlas?
     
    Last edited: Sep 22, 2014
  9. Xylph

    Xylph

    Joined:
    Dec 11, 2013
    Posts:
    29
    I wrote an editor script to generate usable bitmap fonts and based the parsing algorithm on a code snippet I found in the net. I've only tested this with Littera using XML format (.fnt)

    This code was written in 4.6b20 and should work on the latest RC build.

    HOW TO USE:
    Right click on the exported .fnt file (make sure it's in the same directory as the font atlas) then click on "Generate Bitmap Font". This will create the .fontsettings file (Unity font) and a material for it.

    After generating, make sure to set "Line Spacing" of the font asset to the target font size. Font API doesn't let me modify it, so you need to do it manually :)

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System;
    4. using UnityEditor;
    5. using System.IO;
    6. using System.Xml;
    7.  
    8. public static class BitmapFontImporter {
    9.  
    10.     [MenuItem("Assets/Generate Bitmap Font")]
    11.     public static void GenerateFont()
    12.     {
    13.         TextAsset selected = (TextAsset)Selection.activeObject;
    14.         string rootPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(selected));
    15.  
    16.         Texture2D texture = AssetDatabase.LoadAssetAtPath(rootPath + "/" + selected.name + ".png", typeof(Texture2D)) as Texture2D;
    17.         if (!texture) throw new UnityException("Texture2d asset doesn't exist for " + selected.name);
    18.  
    19.         string exportPath = rootPath + "/" + Path.GetFileNameWithoutExtension(selected.name);
    20.  
    21.         Work(selected, exportPath, texture);
    22.     }
    23.  
    24.  
    25.     private static void Work(TextAsset import, string exportPath, Texture2D texture)
    26.     {
    27.         if (!import) throw new UnityException(import.name + "is not a valid font-xml file");
    28.  
    29.         Font font = new Font();
    30.      
    31.         XmlDocument xml = new XmlDocument();
    32.         xml.LoadXml(import.text);
    33.      
    34.         XmlNode info = xml.GetElementsByTagName("info")[0];
    35.         XmlNode common = xml.GetElementsByTagName("common")[0];
    36.         XmlNodeList chars = xml.GetElementsByTagName("chars") [0].ChildNodes;
    37.  
    38.         float texW = texture.width;
    39.         float texH = texture.height;
    40.      
    41.         CharacterInfo[] charInfos = new CharacterInfo[chars.Count];
    42.         Rect r;
    43.      
    44.         for (int i=0; i<chars.Count; i++)
    45.         {
    46.             XmlNode charNode = chars[i];
    47.             CharacterInfo charInfo = new CharacterInfo();
    48.          
    49.             charInfo.index = ToInt(charNode, "id");
    50.             charInfo.width = ToInt(charNode, "xadvance");
    51.             charInfo.flipped = false;
    52.          
    53.             r = new Rect();
    54.             r.x = ((float) ToInt(charNode, "x")) / texW;
    55.             r.y = ((float) ToInt(charNode, "y")) / texH;
    56.             r.width = ((float) ToInt(charNode, "width")) / texW;
    57.             r.height = ((float) ToInt(charNode, "height")) / texH;
    58.             r.y = 1f - r.y - r.height;
    59.             charInfo.uv = r;
    60.          
    61.          
    62.             r = new Rect();
    63.             r.x = (float) ToInt(charNode, "xoffset");
    64.             r.y = (float) ToInt(charNode, "yoffset");
    65.             r.width = (float) ToInt(charNode, "width");
    66.             r.height = (float) ToInt(charNode, "height");
    67.             r.y = -r.y;
    68.             r.height = -r.height;
    69.             charInfo.vert = r;
    70.          
    71.             charInfos[i] = charInfo;
    72.         }
    73.  
    74.         // Create material
    75.         Shader shader = Shader.Find("UI/Default");
    76.         Material material = new Material(shader);
    77.         material.mainTexture = texture;
    78.         AssetDatabase.CreateAsset(material, exportPath + ".mat");
    79.  
    80.         // Create font
    81.         font.material = material;
    82.         font.name = info.Attributes.GetNamedItem("face").InnerText;
    83.         font.characterInfo = charInfos;
    84.         AssetDatabase.CreateAsset(font, exportPath + ".fontsettings");
    85.     }
    86.  
    87.     private static int ToInt(XmlNode node, string name)
    88.     {
    89.         return Convert.ToInt32(node.Attributes.GetNamedItem(name).InnerText);
    90.     }
    91. }
    92.  
     
    drHogan, funshark and rakkarage like this.
  10. NicolasHognon

    NicolasHognon

    Joined:
    Nov 15, 2010
    Posts:
    31
    Hello Xylph,

    Thank you for your script. I think it will help me. I try to use it with an xml file generated with shoebox. It is the same format you are using but it did not succeed having correct text. I cannot understand why but character are not correctly aligned. Even if the value of the xml file seems ok. I try to modified value of the generated found manually but did not succeed to understand which value should be ok. Perhaps the problem comes from my UI.Text.

    I attached the png I am using and here is the xml file

    Code (CSharp):
    1.  
    2. <font>
    3.   <info face="D:\Creative Cloud Files\Chapo\Fonts\distance-export" size="80" />
    4.   <common lineHeight="80" scaleW="161" scaleH="164" pages="1" />
    5.   <pages>
    6.     <page id="0" file="D:\Creative Cloud Files\Chapo\Fonts\distance-export.png" />
    7.   </pages>
    8.   <chars count="13">
    9.     <char id="48" x="0" y="101" width="40" height="54" xoffset="2" yoffset="26" xadvance="41" /><!-- 0 -->
    10.     <char id="49" x="121" y="54" width="39" height="53" xoffset="2" yoffset="26" xadvance="40" /><!-- 1 -->
    11.     <char id="50" x="121" y="0" width="39" height="53" xoffset="2" yoffset="26" xadvance="40" /><!-- 2 -->
    12.     <char id="51" x="81" y="109" width="39" height="54" xoffset="2" yoffset="26" xadvance="40" /><!-- 3 -->
    13.     <char id="52" x="81" y="54" width="39" height="54" xoffset="2" yoffset="26" xadvance="40" /><!-- 4 -->
    14.     <char id="53" x="121" y="108" width="39" height="54" xoffset="2" yoffset="26" xadvance="40" /><!-- 5 -->
    15.     <char id="54" x="41" y="98" width="39" height="56" xoffset="2" yoffset="24" xadvance="40" /><!-- 6 -->
    16.     <char id="55" x="41" y="44" width="39" height="53" xoffset="2" yoffset="27" xadvance="40" /><!-- 7 -->
    17.     <char id="56" x="81" y="0" width="39" height="53" xoffset="2" yoffset="27" xadvance="40" /><!-- 8 -->
    18.     <char id="57" x="0" y="44" width="40" height="56" xoffset="2" yoffset="23" xadvance="41" /><!-- 9 -->
    19.     <char id="109" x="0" y="0" width="44" height="43" xoffset="0" yoffset="37" xadvance="45" /><!-- m -->
    20.     <char id="32" x="0" y="0" width="0" height="0" xoffset="0" yoffset="0" xadvance="20" /><!--   -->
    21.     <char id="9" x="0" y="0" width="0" height="0" xoffset="0" yoffset="0" xadvance="160" /><!--      -->
    22.   </chars>
    23.   <kernings count="0">
    24.   </kernings>
    25. </font>
    26.  
    I also copy an example (as screenshot) of my problem.
    My text only contains "0"
    We can see the 0 but also part of 9,7,6.

    So I also copy a screenshot of my Text component

    I you have any ideas of what to test it will really help me

    Capture d’écran 2014-12-16 à 21.56.59.png

    distance-export.png Capture d’écran 2014-12-16 à 21.55.22.png
     
  11. NicolasHognon

    NicolasHognon

    Joined:
    Nov 15, 2010
    Posts:
    31
    If found my problem : my texture was not power of two so unity3d put it to 256x256. I just need to correctly setup the texture so it keep its resolution.
     
  12. cjf-inc

    cjf-inc

    Joined:
    Aug 18, 2014
    Posts:
    10
  13. Cascho01

    Cascho01

    Joined:
    Mar 19, 2010
    Posts:
    1,076
    Also search for TYPOGENIC...
     
  14. Xylph

    Xylph

    Joined:
    Dec 11, 2013
    Posts:
    29
    Hi, I'm not sure if this will help you but I ran into a similar problem with my other project (if I can remember it correctly). The fix I made with the script was to use floats instead of ints. Anyway here's the edited script. The fix is kinda messy as I just hacked it as fast as I can to make it work (sorry XD)


    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System;
    4. using UnityEditor;
    5. using System.IO;
    6. using System.Xml;
    7.  
    8. public static class BitmapFontImporter {
    9.  
    10.     [MenuItem("Assets/Generate Bitmap Font")]
    11.     public static void GenerateFont()
    12.     {
    13.         TextAsset selected = (TextAsset)Selection.activeObject;
    14.         string rootPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(selected));
    15.  
    16.         Texture2D texture = AssetDatabase.LoadAssetAtPath(rootPath + "/" + selected.name + ".png", typeof(Texture2D)) as Texture2D;
    17.         if (!texture) throw new UnityException("Texture2d asset doesn't exist for " + selected.name);
    18.  
    19.         string exportPath = rootPath + "/" + Path.GetFileNameWithoutExtension(selected.name);
    20.  
    21.         Work(selected, exportPath, texture);
    22.     }
    23.  
    24.  
    25.     private static void Work(TextAsset import, string exportPath, Texture2D texture)
    26.     {
    27.         if (!import) throw new UnityException(import.name + "is not a valid font-xml file");
    28.  
    29.         Font font = new Font();
    30.      
    31.         XmlDocument xml = new XmlDocument();
    32.         xml.LoadXml(import.text);
    33.      
    34.         XmlNode info = xml.GetElementsByTagName("info")[0];
    35.         XmlNode common = xml.GetElementsByTagName("common")[0];
    36.         XmlNodeList chars = xml.GetElementsByTagName("chars") [0].ChildNodes;
    37.  
    38.         float texW = texture.width;
    39.         float texH = texture.height;
    40.      
    41.         CharacterInfo[] charInfos = new CharacterInfo[chars.Count];
    42.         Rect r;
    43.      
    44.         for (int i=0; i<chars.Count; i++)
    45.         {
    46.             XmlNode charNode = chars[i];
    47.             CharacterInfo charInfo = new CharacterInfo();
    48.          
    49.             charInfo.index = (int)ToFloat(charNode, "id");
    50.             charInfo.width = ToFloat(charNode, "xadvance");
    51.             charInfo.flipped = false;
    52.          
    53.             r = new Rect();
    54.             r.x = ((float) ToFloat(charNode, "x")) / texW;
    55.             r.y = ((float) ToFloat(charNode, "y")) / texH;
    56.             r.width = ((float) ToFloat(charNode, "width")) / texW;
    57.             r.height = ((float) ToFloat(charNode, "height")) / texH;
    58.             r.y = 1f - r.y - r.height;
    59.             charInfo.uv = r;
    60.          
    61.          
    62.             r = new Rect();
    63.             r.x = (float) ToFloat(charNode, "xoffset");
    64.             r.y = (float) ToFloat(charNode, "yoffset");
    65.             r.width = (float) ToFloat(charNode, "width");
    66.             r.height = (float) ToFloat(charNode, "height");
    67.             r.y = -r.y;
    68.             r.height = -r.height;
    69.             charInfo.vert = r;
    70.          
    71.             charInfos[i] = charInfo;
    72.         }
    73.  
    74.         // Create material
    75.         Shader shader = Shader.Find("UI/Default");
    76.         Material material = new Material(shader);
    77.         material.mainTexture = texture;
    78.         AssetDatabase.CreateAsset(material, exportPath + ".mat");
    79.  
    80.         // Create font
    81.         font.material = material;
    82.         font.name = info.Attributes.GetNamedItem("face").InnerText;
    83.         font.characterInfo = charInfos;
    84.         AssetDatabase.CreateAsset(font, exportPath + ".fontsettings");
    85.     }
    86.  
    87.     private static float ToFloat(XmlNode node, string name)
    88.     {
    89.         return float.Parse(node.Attributes.GetNamedItem(name).InnerText);
    90.     }
    91. }
    92.  
    And yes I'm always using power of two for the texture. Just want to update you if it goes weird on other exports.
     
  15. robotunity

    robotunity

    Joined:
    Mar 20, 2014
    Posts:
    6
    Thank you VERY much for this!

    It works for me, but I was getting a NULL reference error on Shader.Find("UI/Default").

    I had to change it to: Shader.Find("Unlit/Transparent").
     
  16. BenoitFreslon

    BenoitFreslon

    Joined:
    Jan 16, 2013
    Posts:
    119
    Hello,

    I would like to use your script but I got this error when I try to import the bitmap with a .fnt

    NullReferenceException: Object reference not set to an instance of an object
    BitmapFontImporter.ToFloat (System.Xml.XmlNode node, System.String name) (at BitmapFontImporter.cs:92)
    BitmapFontImporter.Work (UnityEngine.TextAsset import, System.String exportPath, UnityEngine.Texture2D texture) (at BitmapFontImporter.cs:51)
    BitmapFontImporter.GenerateFont () (at BitmapFontImporter.cs:23)

    return float.Parse (node.Attributes.GetNamedItem (name).InnerText);

     
  17. BenoitFreslon

    BenoitFreslon

    Joined:
    Jan 16, 2013
    Posts:
    119
    Ok I fixed the bug by adding one line:

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System;
    4. using UnityEditor;
    5. using System.IO;
    6. using System.Xml;
    7.  
    8. public static class BitmapFontImporter
    9. {
    10.  
    11.     [MenuItem("Assets/Generate Bitmap Font")]
    12.     public static void GenerateFont ()
    13.     {
    14.         TextAsset selected = (TextAsset)Selection.activeObject;
    15.         string rootPath = Path.GetDirectoryName (AssetDatabase.GetAssetPath (selected));
    16.      
    17.         Texture2D texture = AssetDatabase.LoadAssetAtPath (rootPath + "/" + selected.name + ".png", typeof(Texture2D)) as Texture2D;
    18.         if (!texture)
    19.             throw new UnityException ("Texture2d asset doesn't exist for " + selected.name);
    20.      
    21.         string exportPath = rootPath + "/" + Path.GetFileNameWithoutExtension (selected.name);
    22.      
    23.         Work (selected, exportPath, texture);
    24.     }
    25.  
    26.  
    27.     private static void Work (TextAsset import, string exportPath, Texture2D texture)
    28.     {
    29.         if (!import)
    30.             throw new UnityException (import.name + "is not a valid font-xml file");
    31.      
    32.         Font font = new Font ();
    33.      
    34.         XmlDocument xml = new XmlDocument ();
    35.         xml.LoadXml (import.text);
    36.      
    37.         XmlNode info = xml.GetElementsByTagName ("info") [0];
    38.         XmlNode common = xml.GetElementsByTagName ("common") [0];
    39.         XmlNodeList chars = xml.GetElementsByTagName ("chars") [0].ChildNodes;
    40.      
    41.         float texW = texture.width;
    42.         float texH = texture.height;
    43.      
    44.         CharacterInfo[] charInfos = new CharacterInfo[chars.Count];
    45.         Rect r;
    46.      
    47.         for (int i=0; i<chars.Count; i++) {
    48.             XmlNode charNode = chars [i];
    49.             if (charNode.Attributes != null) {
    50.                 CharacterInfo charInfo = new CharacterInfo ();
    51.          
    52.                 charInfo.index = (int)ToFloat (charNode, "id");
    53.                 charInfo.width = ToFloat (charNode, "xadvance");
    54.                 charInfo.flipped = false;
    55.          
    56.                 r = new Rect ();
    57.                 r.x = ((float)ToFloat (charNode, "x")) / texW;
    58.                 r.y = ((float)ToFloat (charNode, "y")) / texH;
    59.                 r.width = ((float)ToFloat (charNode, "width")) / texW;
    60.                 r.height = ((float)ToFloat (charNode, "height")) / texH;
    61.                 r.y = 1f - r.y - r.height;
    62.                 charInfo.uv = r;
    63.          
    64.          
    65.                 r = new Rect ();
    66.                 r.x = (float)ToFloat (charNode, "xoffset");
    67.                 r.y = (float)ToFloat (charNode, "yoffset");
    68.                 r.width = (float)ToFloat (charNode, "width");
    69.                 r.height = (float)ToFloat (charNode, "height");
    70.                 r.y = -r.y;
    71.                 r.height = -r.height;
    72.                 charInfo.vert = r;
    73.          
    74.                 charInfos [i] = charInfo;
    75.             }
    76.         }
    77.      
    78.         // Create material
    79.         Shader shader = Shader.Find ("UI/Default");
    80.         Material material = new Material (shader);
    81.         material.mainTexture = texture;
    82.         AssetDatabase.CreateAsset (material, exportPath + ".mat");
    83.      
    84.         // Create font
    85.         font.material = material;
    86.         font.name = info.Attributes.GetNamedItem ("face").InnerText;
    87.         font.characterInfo = charInfos;
    88.         AssetDatabase.CreateAsset (font, exportPath + ".fontsettings");
    89.     }
    90.  
    91.     private static float ToFloat (XmlNode node, string name)
    92.     {
    93.         return float.Parse (node.Attributes.GetNamedItem (name).InnerText);
    94.     }
    95. }
     
    Last edited: Mar 21, 2015
  18. BenoitFreslon

    BenoitFreslon

    Joined:
    Jan 16, 2013
    Posts:
    119
  19. Arhspros

    Arhspros

    Joined:
    Nov 11, 2014
    Posts:
    12
    Thanks for your
     
  20. BenoitFreslon

    BenoitFreslon

    Joined:
    Jan 16, 2013
    Posts:
    119
    Fattie and tomandjerry-tas like this.
  21. tomandjerry-tas

    tomandjerry-tas

    Joined:
    Feb 7, 2013
    Posts:
    21
  22. exawon

    exawon

    Joined:
    Dec 9, 2013
    Posts:
    12
    Jack_JH and rakkarage like this.
  23. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    408
    exawon, that looks totally amazing but it's too much to use the zip package :O
     
  24. Fattie

    Fattie

    Joined:
    Jul 5, 2012
    Posts:
    408
    THIS IS INCREDIBLE......


    tiny tip for users: if you accidentally make text, not XML style, it just crashes. No problem, in GlyphDesigner just choose xml output.

    MERCI, BENOIT !!!
     
  25. exawon

    exawon

    Joined:
    Dec 9, 2013
    Posts:
    12
    Hi, Fattie.

    The font files are in the zip when I get it from http://kvazars.com/littera/
    Otherwise, zip is not essential.

    I will improve the code next time in order to fit it to general purpose.
    You may comment out all about zip before that.

    Thank you for your opinion.