Unity的UGUI中使用CustomFont(BMFont)

原创 2015年11月21日 14:07:28

        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坐标是左下角为原点。

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

UGUI中使用位图艺术字(使用BMfont的两种方式)

第一种方式实现:   NGUI中有 动态字体, BMFont (从官网下载就是一个  .exe  文件! http://www.angelcode.com/products/bmfont/  ) BM...

UGUI 使用BMFont

UGUI 使用BMFont首先要知道 Custom Font 的原理,不知道的同学可以先看这篇[Custom Font 原理](http://blog.csdn.net/liqiangeastsun/...

用BMFont做UGUI美术字体

项目中经常会用到数字图片来显示玩家战力、战斗中的伤害数等,可以借助BMFont来制作一种字体,步骤如下: 1,先位图字体制作工具在电脑上安装好BMFont软件(位图字体制作工具),安装好之后打开如下:...

【Unity】UGUI 如何使用CustomFont(自定义字体)

说在前面 这是我的第一篇博客, 之后慢慢试水搬一些自己曾用到的博客,还有一些自己尝试出来的东西。我深知自己还远远不够,若是有人看到了我的博客,请给我提意见吧~ 若是转载 ,请注明出处喵喵丸的Bl...

【Unity3D ugui】使用艺术字

目录(?)[-]为什么要写这篇艺术字制作流程最终效果需要注意的问题为什么要写这篇其实很早之前就有大神研究出来如何在ugui中使用艺术字,这里奉上文档。之所以再来重复一遍,是因为今天遇到一个问题:在手机...
  • Kaitiren
  • Kaitiren
  • 2015年08月04日 19:52
  • 13091

unity font研究小结

项目用ngui制作的界面,字体使用了unity默认的Arial,打包到
  • cp1001
  • cp1001
  • 2014年06月17日 00:39
  • 4863

Unity3d NGUI系列教程四(自定义Atlas,Font)

今天我们来看一下怎么自定义NGUIAtlas,制作属于自己风格的UI。 第一部分:自定义 Atlas 1 . 首先我们要准备一些图标素材,也就是我们的UI素材,将其导入到unity工程中。 2....

Unity3D-新版本5.5自定义图片字体(Custom Font)的使用

在网上看到很多资料,都是用的以前老的属性了,强迫症发作,只好自己动手将过期的属性都改了 本来是方法我是从网上找的,自己懒得去解析fnt文件了,于是想到了以前用的NGUI就有专门处理fnt文件的类,于是...
  • pz789as
  • pz789as
  • 2017年01月05日 15:05
  • 2031

Unity3D-将美术提供的图片当做字体使用(普通图片自动生成Custom font)

我在上一篇文章中写了一个最新版本的导出fnt字体的方式,主要就是uv和vert的变化。 这两天发现,有时候我们需要的艺术字体,并不是ttf这种字体格式的文件,而有可能是美术人员自己动手画的艺术字,这个...
  • pz789as
  • pz789as
  • 2017年01月10日 14:18
  • 2869

Unity 自定义字体 Custom Font 原理 二

Unity 自定义字体 Custom Font 原理 二接上一篇做好的自定义字体库,以它为例 选中字体库,在Inspector面板显示出来它的所有属性 下面挑选几个属性:(1)Ascii Star...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Unity的UGUI中使用CustomFont(BMFont)
举报原因:
原因补充:

(最多只允许输入30个字)