使用BMFont创建适用于Unity的艺术字

最近经常使用艺术字,虽然之前的工作经验我知道只需要修什么哪些就可以弄好艺术字的创建和间隔,所以打算做个总结,接下来分为以下几步(其中会有补充,最后会有如何解决unity艺术字的字距问题)

第1步 下载BMFont

去官网下载即可BMFont官网,解压,64位就运行64位的exe程序

第2步 生成fnt文件

这里以0-9的数字图片为例子,图片如下:

打开之后,打开Options->Exprot Options,修改字体输出设置

至于内边距和间距一般不用管,然后打开Edit->Open Image Manager,点击Image,三个选项从上到下分别是导入图片、编辑图片(需要点击选中某行)、删除图片(同前一样需要选中)

这里点击导入图片,选中你的图片,假设你选的字符是0,那么选择好图片后,出现了这个页面,检查路径没问题,接下来是填入替换字符的id

如下图,鼠标放到替换字符处,前面的第一个就是id,该id为48,确定之后,开始选中这些需要导出的字符,亮色的就是选中的,左下角有你选中字符数

然后输出即可

补充:

BMFont官网文档

第三步 使用unity生成字体文件(.fontsettings)

添加脚本(非本人所写,这是我觉得写的不错的一个脚本)

,使用也很简单,只需要把.fnt和生成的图集一起导入unity,然后是三个参数的导入,fnt文件拖入第一个框内,第二个可以直接省略,第三个也可以省略,然后直接点击生成,字体就会出现在和fnt文件同目录下

文章链接:https://blog.csdn.net/w0100746363/article/details/105637683

using System.Collections.Generic;
using System.IO;
using System.Xml;
using UnityEditor;
using UnityEngine;public class BMFont : EditorWindow
{private TextAsset _fontTextAsset;private Texture _fontTexture;private string _fontsDir;[MenuItem("FontTools/BMFont", false, 12)]private static void BMFontTools(){BMFont bmFont = new BMFont();bmFont.Show();}private string _getAssetPath(string path){string pathTemp = path.Replace("\\", "/");pathTemp = pathTemp.Replace(Application.dataPath, "Assets");return pathTemp;}void OnGUI(){EditorGUILayout.BeginVertical();TextAsset taTemp = EditorGUILayout.ObjectField("选择Font文件:", _fontTextAsset, typeof(TextAsset), true) as TextAsset;if (taTemp != _fontTextAsset && taTemp != null){string assetDir = Directory.GetParent(AssetDatabase.GetAssetPath(taTemp)).FullName;assetDir = _getAssetPath(assetDir);string imgPath = string.Format("{0}/{1}_0.png", assetDir, taTemp.name);_fontTexture = AssetDatabase.LoadAssetAtPath<Texture>(imgPath);_fontsDir = string.Format("{0}.fontsettings", Path.Combine(assetDir, taTemp.name));if (_fontTexture == null){_fontsDir = string.Empty;Debug.LogError(string.Format("未发现{0}文件", imgPath));}}_fontTextAsset = taTemp;_fontTexture = EditorGUILayout.ObjectField("选择Font图片文件:", _fontTexture, typeof(Texture), true) as Texture;GUI.enabled = false;_fontsDir = EditorGUILayout.TextField("字体生成路径:", _fontsDir);GUI.enabled = true;if (GUILayout.Button("Generate Font")){if (!string.IsNullOrEmpty(_fontsDir)){Material mat = AssetDatabase.LoadAssetAtPath<Material>(_fontsDir.Replace(".fontsettings", ".mat"));if (mat == null){mat = new Material(Shader.Find("UI/Default Font"));AssetDatabase.CreateAsset(mat, _fontsDir.Replace(".fontsettings", ".mat"));}if (_fontTexture != null){mat = AssetDatabase.LoadAssetAtPath<Material>(_fontsDir.Replace(".fontsettings", ".mat"));mat.SetTexture("_MainTex", _fontTexture);}else{Debug.LogError("贴图未做配置,请检查配置");return;}Font font = AssetDatabase.LoadAssetAtPath<Font>(_fontsDir);if (font == null){font = new Font();AssetDatabase.CreateAsset(font, _fontsDir);}_setFontInfo(AssetDatabase.LoadAssetAtPath<Font>(_fontsDir),AssetDatabase.GetAssetPath(_fontTextAsset),_fontTexture);font = AssetDatabase.LoadAssetAtPath<Font>(_fontsDir);font.material = mat;}else{Debug.LogError("创建失败,请检查配置");}}EditorGUILayout.EndVertical();}private void _setFontInfo(Font font, string fontConfig, Texture texture){XmlDocument xml = new XmlDocument();xml.Load(fontConfig);List<CharacterInfo> chtInfoList = new List<CharacterInfo>();XmlNode node = xml.SelectSingleNode("font/chars");foreach (XmlNode nd in node.ChildNodes){XmlElement xe = (XmlElement)nd;int x = int.Parse(xe.GetAttribute("x"));int y = int.Parse(xe.GetAttribute("y"));int width = int.Parse(xe.GetAttribute("width"));int height = int.Parse(xe.GetAttribute("height"));int advance = int.Parse(xe.GetAttribute("xadvance"));CharacterInfo info = new CharacterInfo();info.glyphHeight = texture.height;info.glyphWidth = texture.width;info.index = int.Parse(xe.GetAttribute("id"));//这里注意下UV坐标系和从BMFont里得到的信息的坐标系是不一样的哦,前者左下角为(0,0),//右上角为(1,1)。而后者则是左上角上角为(0,0),右下角为(图宽,图高)info.uvTopLeft = new Vector2((float)x / texture.width, 1 - (float)y / texture.height);info.uvTopRight = new Vector2((float)(x + width) / texture.width, 1 - (float)y / texture.height);info.uvBottomLeft = new Vector2((float)x / texture.width, 1 - (float)(y + height) / texture.height);info.uvBottomRight = new Vector2((float)(x + width) / texture.width, 1 - (float)(y + height) / texture.height);info.minX = 0;info.minY = -height;info.maxX = width;info.maxY = 0;info.advance = advance;chtInfoList.Add(info);}font.characterInfo = chtInfoList.ToArray();AssetDatabase.Refresh();}
}

其中代码最关键的部分就是BMFont的uv坐标转换到unity下的uv坐标,这里代码的意思也很简单就是循环取出图集中的每张图(制作fnt字体时不是有张图吗,那个就是图集),然后每张图转换uv坐标即可。

BMFont的uv坐标,左上角(0,0),右下角为(宽度,高度)

Unity的uv坐标,左下角(0,0),右上角(1,1)

计算就如下图(自己打的手稿哈哈)

UV坐标是建立在一张图(纹理)上的。UV坐标是一个二维坐标系统,用于指定纹理图像上的具体位置,以便将纹理映射到三维模型的表面或二维图形上。这里的“一张图”指的是纹理图像,它包含了将要被映射的像素数据。

uv坐标参考博客:

Unity里的UV到底是什么 - cancantrbl - 博客园

Unity中Mesh的uv坐标讨论与使用方法_unity mesh uv-CSDN博客

解决unity艺术字的字距

通过 Tracking 设置可修改每个字符与同一行下一个字符的接近程度,而通过 Line spacing 设置可定义每行与下一行的接近程度

了解Font文件:Unity官网文档

注意

修改Tracking后需要运行(重新编译后才会生效)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/889417.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

websocket_asyncio

WebSocket 和 asyncio 指南 简介 本指南涵盖了使用 Python 中的 websockets 库进行 WebSocket 编程的基础知识&#xff0c;以及 asyncio 在异步非阻塞 I/O 中的作用。它提供了构建高效 WebSocket 服务端和客户端的知识&#xff0c;以及 asyncio 的特性和优势。 1. 什么是 WebS…

数据结构_树表的查找

平衡调整方法 四种类型的调整 LL型调整 RR型调整 LR型调整 RL型调整 // 以p为根的二叉排序树作右旋处理(LL void BST::rRotate(BiNode*& p) {BiNode* k p->lChild;p->lChild k->rChild;k->rChild p;p k; }// 以p为根的二叉排序树作左旋处理(RR void BST:…

51c~Pytorch~合集2

我自己的原文哦~ https://blog.51cto.com/whaosoft/11878447 一、PyTorch与torch-xla的桥接 文章从XLATensor开始的溯源、注册PyTorch库实现、从PyTorch调用到torch_xla三个方面来介绍PyTorch与torch-xla的桥接 XLA (Accelerated Linear Algebra)是一个开源的机器学习编…

TMS320C55x DSP芯片结构和CPU外围电路

第2章 DSP芯片结构和CPU外围电路 文章目录 第2章 DSP芯片结构和CPU外围电路TMS320C55x处理器的特点TMS320c55x CPU单元指令缓冲(Instruction Buffer Unit) I单元程序流程(Program Flow Unit) P单元地址数据(Address-data Flow Unit) A单元数据计算(Data Computation Unit) D单元…

实战攻防中针对JS路径的泄露和Webpack漏洞的初探

0x1前言 浅谈 这篇文章给师傅们分享下前段时间跟其他师傅学习和交流的Webpack相关漏洞&#xff0c;这个漏洞相对来说比较冷门&#xff0c;在web漏洞中不是那么的热度高&#xff0c;但是平常去挖掘和发现这个漏洞相对来说还是不难的。 后面要是有机会可以给师傅们分享下油猴的…

【人工智能基础08】卷积神经网络习题:卷积神经网络计算、图像填充、卷积的表达与设计

文章目录 1. 卷积核计算2. 卷积神经网络计算3. 卷积核关注的特征问题解答水平边缘检测与水平条纹检测45度条纹检测 4. 图像检测5. 卷积网络是特殊的全连接网络6. 输出矩阵的三种填充方法7. 卷积设计8.9 成像公式10. 卷积的计算次数11. 全连接层的计算 1. 卷积核计算 卷积操作过…

音乐网站设计与实现

文末获取源码和万字论文&#xff0c;制作不易&#xff0c;感谢点赞支持。 音乐网站设计与实现 摘 要 本音乐网站是针对目前音乐网站管理的实际需求&#xff0c;从实际工作出发&#xff0c;对过去的音乐网站管理系统存在的问题进行分析&#xff0c;结合计算机系统的结构、概念、…

【机器学习】在向量的流光中,揽数理星河为衣,以线性代数为钥,轻启机器学习黎明的瑰丽诗章

文章目录 线性代数入门&#xff1a;机器学习零基础小白指南前言一、向量&#xff1a;数据的基本单元1.1 什么是向量&#xff1f;1.1.1 举个例子&#xff1a; 1.2 向量的表示与维度1.2.1 向量的维度1.2.2 向量的表示方法 1.3 向量的基本运算1.3.1 向量加法1.3.2 向量的数乘1.3.3…

SpringBoot——分层解耦、IOC、依赖注入

三层架构 如下图&#xff0c;创建Dao的接口以及该接口的实现类&#xff0c;Service也一样 Dao // Dao接口 public interface UserDao {public List<String> findAll(); }// Dao接口的实现 public class UserDaoImpl implements UserDao {// 加载用户数据Overridepublic …

【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】

目录&#x1f60b; 任务描述 相关知识 测试说明 我的通关代码: 测试结果&#xff1a; 任务描述 本关任务&#xff1a;编写一个程序利用栈判断左、右圆括号是否配对。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a;栈对括号的处理。 栈对括号的处理 &…

企业级日志分析系统ELK之ELK概述

ELK 概述 ELK 介绍 什么是 ELK 早期IT架构中的系统和应用的日志分散在不同的主机和文件&#xff0c;如果应用出现问题&#xff0c;开发和运维人员想排 查原因&#xff0c;就要先找到相应的主机上的日志文件再进行查找和分析&#xff0c;所以非常不方便&#xff0c;而且还涉及…

pyqt+ubuntu18.04+designer+测试是否安装成功

引用&#xff1a; Ubuntu Linux安装PyQt5并配置Qt Designer 在Visual Studio Code中使用PyQt5开发python GUI应用程序 Linux环境下在Vscode中安装和设置PyQt5插件 其中&#xff0c; 测试是否安装成功 1、设置好之后在vscode编辑器的左侧文件目录栏空白位置右键&#xff0…

torchaudio.load 段错误

使用 torchaudio.load 时出现崩溃&#xff0c;如图 解决&#xff1a; 安装 ffmpeg ​conda install ffmpeg -c conda-forge 尝试但没解决问题的方法包括 重装 cuda&#xff0c;重装 pytorch&#xff0c;安装 PySoundFile、SoundFile、sox。

React 第十六节 useCallback 使用详解注意事项

useCallback 概述 1、useCallback 是在React 中多次渲染缓存函数的 Hook&#xff0c;返回一个函数的 memoized的值&#xff1b; 2、如果多次传入的依赖项不变&#xff0c;那么多次定义的时候&#xff0c;返回的值是相同的,防止频繁触发更新&#xff1b; 3、多应用在 父组件为函…

Chrome webdriver下载-避坑

WebDriver以原生的方式驱动浏览器&#xff0c;不需要调整环境变量。 一、window版 1.chrome和chromedriver下载地址&#xff1a; Chrome for Testing availability 我下载的是如下两个安装包&#xff0c;解压即可。 2.导包 pip install selenium然后用python代码引用即可…

PyQt事件机制练习

一、思维导图 二、代码 import sysfrom PyQt6.QtTextToSpeech import QTextToSpeech from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QLineEdit from PyQt6 import uic from PyQt6.QtCore import Qt, QTimerEvent, QTimeclass MyWidget(QWidget):d…

【Rive】Android与Rive交互

1 Android与Rive交互的常用接口 1.1 RiveAnimationView参数 <app.rive.runtime.kotlin.RiveAnimationViewandroid:id"id/rive_view"android:layout_width"match_parent"android:layout_height"match_parent"android:adjustViewBounds"…

Maven、mybatis框架

一、Maven介绍 1.概念&#xff1a; Maven项目对象模型(POM)&#xff0c;可以通过一小段描述信息来管理项目的构建&#xff0c;报告和文档的项目管理工具软件。 2.为啥使用maven: 之前项目中需要引入大量的jar包。这些jar从网上下载&#xff0c;可能下载地址不同意。这些jar之间…

使用 Python 爬取某网站简历模板(bs4/lxml+协程)

使用 Python 爬取站长素材简历模板 简介 在本教程中&#xff0c;我们将学习如何使用 Python 来爬取站长素材网站上的简历模板。我们将使用requests和BeautifulSoup库来发送 HTTP 请求和解析 HTML 页面。本教程将分为两个部分&#xff1a;第一部分是使用BeautifulSoup的方法&am…

HCIA-Access V2.5_2_2网络通信基础_TCP/IP协议栈报文封装

TCP/IP协议栈的封装过程 用户从应用层发出数据先会交给传输层&#xff0c;传输层会添加TCP或者UDP头部&#xff0c;然后交给网络层&#xff0c;网络层会添加IP头部&#xff0c;然后交给数据链路层&#xff0c;数据链路层会添加以太网头部和以太网尾部&#xff0c;最后变成01这样…