UnityのUGUIではCustomFont(BMFont)を使用

6285 ワード

UnityのUGUIの文字レンダリング効率は高いはずですが、一般的にはデフォルトのTextコントロールでTTFのFontが需要を満たしています.しかし、芸術フォントをレンダリングする必要がある場合はBMFontを使用する必要があります.
一、BMFontの基本使用は、fntフォントを作成する手順は多くありません.ここで、BMFontはコマンドラインをサポートしています.ここに私が使っているスクリプトを貼って、フォントを更新するのが便利です. 
        bmfcファイルはBMFontのプロファイルであり、BMFontのGUIプログラムを使用して対応するフォントプロファイル(テクスチャサイズ、特殊文字の画像へのマッピング関係などを含む)を設定して保存します.
        txtファイルは、フォントを生成する必要があるすべての文字を含む純粋なテキストです.
# -*- coding: utf-8 -*-
import os,sys,shutil,subprocess,glob

global SOURCE_PATH
global TARGET_PATH

SOURCE_PATH = 'font/'
TARGET_PATH = '../Assets/Font'
COMMON_TEXT = "text.txt"
CMD = 'support/BMFont/bmfont.exe'

def genFont(configPath, txtPath):
    fntPath = configPath.replace('.bmfc', '.fnt');
    pngPathOld = configPath.replace('.bmfc', '_0.png');
    pngPathNew = configPath.replace('.bmfc', '.png');

    subprocess.call('"{0}" -c {1} -o {2} -t {3}'.format(CMD, configPath, fntPath, txtPath))
    if os.path.exists(pngPathNew):
        os.remove(pngPathNew);
    os.rename(pngPathOld, pngPathNew);

    fileData = []
    fp = open(fntPath, 'r');
    for line in fp:
        if line.find('file="') != -1:
            fileData.append(line.replace('_0.png', '.png'));
        else:
            fileData.append(line);
    fp.close();
    fpw = open(fntPath, 'w');
    fpw.writelines(fileData);


fileList = glob.glob(SOURCE_PATH + '*.bmfc')
for file in fileList:
    txtFile = file.replace(".bmfc", ".txt")
    if os.path.exists(txtFile):
        genFont(file,  txtFile)
    else:
        genFont(file, COMMON_TEXT)

os.system('PAUSE')

二、Unityの特殊なフォントはCustomFontを使用します.CustomFontは、ttfフォントと等価なリソースで、フォントのフォント情報などのデータが含まれています.以前、NGUIにはfntファイルからCustomFontを作成するスクリプトがありました.似たようなことをするためのスクリプトを書きました.
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;

//   bmfont
public class CreateFontEditor : Editor
{
    [MenuItem("Assets/CreateBMFont")]
    static void CreateFont()
    {
        Object obj = Selection.activeObject;
        string fntPath = AssetDatabase.GetAssetPath(obj);
        if (fntPath.IndexOf(".fnt") == -1) {
            //       
            return;
        }

        string customFontPath = fntPath.Replace(".fnt", ".fontsettings");
        if (!File.Exists(customFontPath)) {
            return;
        }

        Debug.Log(fntPath);
        StreamReader reader = new StreamReader(new FileStream(fntPath, FileMode.Open));

        List<CharacterInfo> charList = new List<CharacterInfo>();

        Regex reg = new Regex(@"char id=(?<id>\d+)\s+x=(?<x>\d+)\s+y=(?<y>\d+)\s+width=(?<width>\d+)\s+height=(?<height>\d+)\s+xoffset=(?<xoffset>\d+)\s+yoffset=(?<yoffset>\d+)\s+xadvance=(?<xadvance>\d+)\s+");
        string line = reader.ReadLine();
        int lineHeight = 0;
        int texWidth = 1;
        int texHeight = 1;

        while (line != null) {
            if (line.IndexOf("char id=") != -1) {
                Match match = reg.Match(line);
                if (match != Match.Empty) {
                    var id = System.Convert.ToInt32(match.Groups["id"].Value);
                    var x = System.Convert.ToInt32(match.Groups["x"].Value);
                    var y = System.Convert.ToInt32(match.Groups["y"].Value);
                    var width = System.Convert.ToInt32(match.Groups["width"].Value);
                    var height = System.Convert.ToInt32(match.Groups["height"].Value);
                    var xoffset = System.Convert.ToInt32(match.Groups["xoffset"].Value);
                    var yoffset = System.Convert.ToInt32(match.Groups["yoffset"].Value);
                    var xadvance = System.Convert.ToInt32(match.Groups["xadvance"].Value);

                    CharacterInfo info = new CharacterInfo();
                    info.index = id;
                    float uvx = 1f*x/texWidth;
                    float uvy = 1 - (1f*y/texHeight);
                    float uvw = 1f*width/texWidth;
                    float uvh = -1f*height/texHeight;

                    info.uvBottomLeft = new Vector2(uvx, uvy);
                    info.uvBottomRight = new Vector2(uvx + uvw, uvy);
                    info.uvTopLeft = new Vector2(uvx, uvy + uvh);
                    info.uvTopRight = new Vector2(uvx + uvw, uvy + uvh);

                    info.minX = xoffset;
                    info.minY = yoffset + height / 2;   //          ok ,    
                    info.glyphWidth = width;
                    info.glyphHeight = -height; //   ,          ,   unity  uv  
                    info.advance = xadvance;

                    charList.Add(info);
                }
            } else if (line.IndexOf("scaleW=") != -1) {
                Regex reg2 = new Regex(@"common lineHeight=(?<lineHeight>\d+)\s+.*scaleW=(?<scaleW>\d+)\s+scaleH=(?<scaleH>\d+)");
                Match match = reg2.Match(line);
                if (match != Match.Empty) {
                    lineHeight = System.Convert.ToInt32(match.Groups["lineHeight"].Value);
                    texWidth = System.Convert.ToInt32(match.Groups["scaleW"].Value);
                    texHeight = System.Convert.ToInt32(match.Groups["scaleH"].Value);
                }
            }
            line = reader.ReadLine();
        }

        Font customFont = AssetDatabase.LoadAssetAtPath<Font>(customFontPath);
        customFont.characterInfo = charList.ToArray();
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        Debug.Log(customFont);
    }
}

        ここで少し説明しますが、最終的なFontフォントは、まず手動でUnityにCustomFontファイルを作成し、名前はfntファイルと同じで、対応するMaterialを添付します.Materialは材質で、shaderはGUI/Text Shaderを選択し、画像はBMFontが生成したテクスチャを選択します.ここで少し変更すると、フォントファイルの自動作成がサポートされます.
        このスクリプトでは、fntファイルを読み取り解析し、各字形の座標を取得し、CharactorInfoオブジェクトを作成し、計算後のuv座標を添付し、最終的には早いFontに保存します.unityのuv座標は左下隅が原点であることに注意してください.