Unity的UGUI中使用CustomFont(BMFont)

来源:互联网 发布:淘宝返利网哪个最好 编辑:程序博客网 时间:2024/05/21 11:39

        Unity的UGUI的文字渲染效率应该是挺高的,一般来说用默认的Text控件,TTF的Font就满足需求了。不过有时候需要渲染艺术字体的时候还是需要用到BMFont。

一、BMFont的基础使用,创建fnt字体的步骤就不多说了。这里额外提一下就是BMFont是支持命令行的。这里贴一下我使用的脚本,更新字体比较方便。 

        bmfc文件是BMFont的配置文件,使用BMFont的GUI程序设置并保存好对应的字体配置(配置里面包含纹理大小、特殊字符对图片的映射关系等等)

        txt文件是一个纯文本,包含所需要生成字体的所有文字

# -*- coding: utf-8 -*-import os,sys,shutil,subprocess,globglobal SOURCE_PATHglobal TARGET_PATHSOURCE_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;// 创建bmfontpublic 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坐标是左下角为原点。

1 0