2013/10/05(土) [n年前の日記]
#1 [unity] Unity上でCustom Fontの設定作業が自動化できた
(※ 2013/10/07追記。色々修正した版を
_mieki256/ChrRectSet - GitHub
にアップしておきました。この記事に書いてあるソースは古いです。)
Unity上で Custom Font を使えばビットマップフォントが使えるようになるけれど。
1文字ずつUV座標等をGUIで入力していくのが面倒なので、なんとか自動化できないかと。何せ、1文字につき入力欄が10ヶ所、それを10〜95文字分とか、手入力してられないですわ…。
2種類の設定ができるようにしてみたり。
Unity上で Custom Font を使えばビットマップフォントが使えるようになるけれど。
2種類の設定ができるようにしてみたり。
- BMFontで出力したフォント画像 + .fntファイル(文字配置情報が書かれてる)を使って設定。
- 等間隔に配置されたフォント画像を使って設定。
◎ 使うフォント画像の例。 :
以下は、BMFontで出力したフォント画像の例。(M+フォントを使用。画像は256x256。) ギッチリ詰まってるからテクスチャが無駄にならないけど、計算で場所を求めていくのも、レタッチするのも、たぶん無理。
_配置情報(.fntファイル)
が無いと使えない。
以下は、等間隔で配置されたフォント画像の例。(Molotフォント使用。256x64。数字のみ10文字分。) これなら計算で配置が求められるし、レタッチ等も楽だけど、テクスチャは無駄だらけ。
以下は、等間隔で配置されたフォント画像の例。(Molotフォント使用。256x64。数字のみ10文字分。) これなら計算で配置が求められるし、レタッチ等も楽だけど、テクスチャは無駄だらけ。
◎ スクリプトの導入手順。 :
- Projects に Editor というフォルダを作る。
- Editorフォルダの中に C#ファイルを作成して、ChrRectSet.cs というファイル名にする。
- 下記ソースをコピペして保存。
- Unityのメニューに、Custom という項目が増えてるはず。
◎ 実行手順。 :
Custom → Custom Font Setting → Chr Rect Set を選択。ウインドウが開く。
BMFontの出力画像を使う場合。.fnt は .txt にリネームしておく。
等間隔に配置されたフォント画像を使う場合。
ただ、Setボタンを押して値が設定されても、すぐに変更が反映されるわけではないようで。Custom Font の Character Rects を開いたり閉じたりしてると、なんだかそのうち反映される模様。
BMFontの出力画像を使う場合。.fnt は .txt にリネームしておく。
- Assets から、「Custom Font」「フォント画像」「文字配置情報が書かれたテキストファイル(BMFontが出力した .fnt を .txt にリネームしたもの)」の3つをD&Dで登録。
- Setボタンを押せば、Custom Font の Character Rects に、テーブルファイルの内容が代入される。
等間隔に配置されたフォント画像を使う場合。
- ウインドウ表示後、Assets から、「Custom Font」「フォント画像」の2つをD&Dで登録して、「画像内でフォントが置かれている範囲」「横方向の文字数」「縦方向の文字数」「使う文字数」を入力してSetボタンを押せば設定される。
ただ、Setボタンを押して値が設定されても、すぐに変更が反映されるわけではないようで。Custom Font の Character Rects を開いたり閉じたりしてると、なんだかそのうち反映される模様。
◎ ソースコード。 :
_ChrRectSet.cs
どうせそのうち仕様が変わって使えなくなる予感。つーかフツーはNGUIとやらを買って使うのだろうからこんなの使わんですわな。
using UnityEngine; using UnityEditor; using System.Collections.Generic; /* * BMFontで出力した bitmap font 画像の文字配置情報を * custom Font に設定するUnity拡張。 * * Custom → Custom Font Setting → Chr Rect Set でウインドウを開いて、 * Custom Font、テーブルファイル(.txt)、フォント画像、 * の3つをD&Dで登録して Set ボタンを押せば、 * Custom Font の Character Rects を設定してくれる。 * * 等間隔で配置された bitmpa font 画像に関しても設定できる機能付き。 * Custom Font、フォント画像、 * 画像内でフォント部分が置かれている範囲、 * 横方向の文字個数、縦方向の文字個数、使う文字個数、 * を入力して Set ボタンを押せば設定してくれる。 */ public class ChrRectSet : EditorWindow { public Font customFontObj; public TextAsset fontPosTbl; public Texture fontTexture; public Rect useTexRect = new Rect(0, 0, 256, 256); public int fontCountX = 8; public int fontCountY = 8; public int fontLength = 64; struct ChrRect { public int id; public int x; public int y; public int w; public int h; public int xofs; public int yofs; public int index; public float uvX; public float uvY; public float uvW; public float uvH; public float vertX; public float vertY; public float vertW; public float vertH; public float width; } // メニューに登録 [MenuItem("Custom/Custom Font Setting/Chr Rect Set")] static void Init() { EditorWindow.GetWindow(typeof(ChrRectSet)); } // 表示ウインドウの内容 void OnGUI() { // Custom Font 登録欄 customFontObj = (Font)EditorGUILayout.ObjectField("Custom Font", customFontObj, typeof(Font), false); // フォント画像指定欄 fontTexture = (Texture)EditorGUILayout.ObjectField("Font Texture", fontTexture, typeof(Texture), false, GUILayout.Width(64), GUILayout.Height(64)); // 文字テーブルファイル登録欄 EditorGUILayout.Space(); EditorGUILayout.LabelField("Use Font Table Text File", EditorStyles.boldLabel); fontPosTbl = (TextAsset)EditorGUILayout.ObjectField("Font Table Text File", fontPosTbl, typeof(TextAsset), false); // 実行ボタン if (GUILayout.Button("Set Character Rects")) { if (customFontObj == null) this.ShowNotification(new GUIContent("No Custom Font selected")); else if (fontTexture == null) this.ShowNotification(new GUIContent("No Font Texture selected")); else if (fontPosTbl == null) this.ShowNotification(new GUIContent("No Font Position Table file selected")); else CalcChrRect(customFontObj, fontPosTbl, fontTexture); } // 等分割して設定する場合の入力欄 EditorGUILayout.Space(); EditorGUILayout.LabelField("Grid", EditorStyles.boldLabel); useTexRect = EditorGUILayout.RectField("Use Texture Area", useTexRect); fontCountX = EditorGUILayout.IntField("Font Count X", fontCountX); fontCountY = EditorGUILayout.IntField("Font Count Y", fontCountY); fontLength = EditorGUILayout.IntField("Character Length", fontLength); if (GUILayout.Button("Set Character Rects")) { if (customFontObj == null) this.ShowNotification(new GUIContent("No Custom Font selected")); else if (fontTexture == null) this.ShowNotification(new GUIContent("No Font Texture selected")); else CalcChrRectGrid(customFontObj, fontTexture, useTexRect, fontCountX, fontCountY, fontLength); } } // フォントテーブルを元にして設定 void CalcChrRect(Font fontObj, TextAsset posTbl, Texture tex) { // フォント画像のサイズを取得 float imgw = (float)tex.width; float imgh = (float)tex.height; // 文字テーブルの内容を取得 string txt = posTbl.text; List<ChrRect> tblList = new List<ChrRect>(); int asciiStartOffset = 128; int maxH = 0; foreach (string line in txt.Split('\n')) { if (line.IndexOf("char id=") == 0) { ChrRect d = GetChrRect(line, imgw, imgh); if (asciiStartOffset > d.id) asciiStartOffset = d.id; if (maxH < d.h) maxH = d.h; tblList.Add(d); } } ChrRect[] tbls = tblList.ToArray(); // index値を調整 for (int i = 0; i < tbls.Length; i++) { tbls[i].index = tbls[i].id - asciiStartOffset; } // 新しい CharacterInfo を作成 SetCharacterInfo(tbls, fontObj); } // 等分割して設定 void CalcChrRectGrid(Font fontObj, Texture tex, Rect area, int xc, int yc, int num) { float imgw = (float)tex.width; float imgh = (float)tex.height; int fw = (int)(area.width - area.x) / xc; int fh = (int)(area.height - area.y) / yc; List<ChrRect> tblList = new List<ChrRect>(); for (int i = 0; i < num; i++) { int xi = i % xc; int yi = i / xc; ChrRect d = new ChrRect(); d.index = i; d.uvX = (float)(area.x + (fw * xi)) / imgw; d.uvY = (float)(imgh - (area.y + (fh * yi) + fh)) / imgh; d.uvW = (float)fw / imgw; d.uvH = (float)fh / imgh; d.vertX = 0; d.vertY = 0; d.vertW = fw; d.vertH = -fh; d.width = fw; tblList.Add(d); } ChrRect[] tbls = tblList.ToArray(); SetCharacterInfo(tbls, fontObj); } // 新しい CharacterInfo を Custom Font に上書き設定 void SetCharacterInfo(ChrRect[] tbls, Font fontObj) { CharacterInfo[] nci = new CharacterInfo[tbls.Length]; for (int i = 0; i < tbls.Length; i++) { nci[i].index = tbls[i].index; nci[i].width = tbls[i].width; nci[i].uv.x = tbls[i].uvX; nci[i].uv.y = tbls[i].uvY; nci[i].uv.width = tbls[i].uvW; nci[i].uv.height = tbls[i].uvH; nci[i].vert.x = tbls[i].vertX; nci[i].vert.y = tbls[i].vertY; nci[i].vert.width = tbls[i].vertW; nci[i].vert.height = tbls[i].vertH; } fontObj.characterInfo = nci; } // フォントテーブルの1行分(1文字分)を構造体に記録 ChrRect GetChrRect(string line, float imgw, float imgh) { ChrRect d = new ChrRect(); foreach (string s in line.Split(' ')) { if (s.IndexOf("id=") >= 0) d.id = GetParamInt(s, "id="); else if (s.IndexOf("x=") >= 0) d.x = GetParamInt(s, "x="); else if (s.IndexOf("y=") >= 0) d.y = GetParamInt(s, "y="); else if (s.IndexOf("width=") >= 0) d.w = GetParamInt(s, "width="); else if (s.IndexOf("height=") >= 0) d.h = GetParamInt(s, "height="); else if (s.IndexOf("xoffset=") >= 0) d.xofs = GetParamInt(s, "xoffset="); else if (s.IndexOf("yoffset=") >= 0) d.yofs = GetParamInt(s, "yoffset="); } // Uv情報を算出 d.uvX = (float)d.x / imgw; d.uvY = (float)(imgh - d.y - d.h) / imgh; d.uvW = (float)d.w / imgw; d.uvH = (float)d.h / imgh; // Vert情報を算出 //d.vertX = (float)d.xofs; d.vertX = 0.0f; d.vertY = -(float)d.yofs; d.vertW = d.w; d.vertH = -d.h; // widthを算出 d.width = d.w; return d; } // "wd=数値を示す文字列" を数値にして返す int GetParamInt(string s, string wd) { if (s.IndexOf(wd) >= 0) { int v; if (int.TryParse(s.Substring(wd.Length), out v)) return v; } return int.MaxValue; } }ソースのライセンスは…Unityってそのあたり何か強制されるのかな? 特にそういう制限がないのであれば Public Domain ってことで。
どうせそのうち仕様が変わって使えなくなる予感。つーかフツーはNGUIとやらを買って使うのだろうからこんなの使わんですわな。
[ ツッコむ ]
以上です。