木骰

关于TextMeshPro

TextMeshPro对文本的渲染是基于有向距离场(SDF)算法,相比于Unity原本的ttf字体,在任意距离,缩放尺寸等情况下都能渲染出清晰的文本,而ttf则有可能出现毛边,失真等情况,并且对于一些文字效果,描边,阴影等,TextMeshPro通过Shader实现,相比于原生的Text组件通过增加顶点偏移的方式,渲染效果更好,并且效率也更高。基于这些优点,项目中对于一些文本的显示,可以有选择地使用TextMeshPro。

关于SDF算法

有向距离场算法(Signed Distance Field)。
原生的Text文本组件对文字块的渲染是通过一个字块贴图,这个贴图则来自于ttf字体,贴图上记录了每个像素的颜色信息,当对文本尺寸进行放大缩小时,Text会对像素的颜色进行插值渲染,当颜色插值不准确时就有可能出现模糊失真的情况。

而TextMeshPro使用SDF进行渲染,对于字块贴图上记录的不是像素的颜色信息,而是每个像素到字形边缘的距离,当文本放大缩小时,TextMeshPro对像素到字形边缘的距离进行插值,而不是对颜色插值,也就是说此处得到的一个字形的轮廓区域,并没有马上得到每个像素的颜色,如果用01来表示的话,相当于就是把落在字块上的像素全部标1,然后再进行上色。这样就不存在对颜色插值不准确造成的失真问题,因为对距离的插值总是可以得到一个清晰的字形轮廓。

关于ttf字体

除了渲染效果更好之外,TextMeshPro在性能上也有一些优势。先看看原本的ttf存在的一些问题。

关于ttf的动态字体渲染模式的问题。

Alt text
一般使用ttf字体也都是选择的动态字体渲染模式,动态渲染模式可以再渲染字体的时候根据当前text组件显示的文本内容上用到的字符来动态创建文本贴图,这样可以不至于在一开始的时候就创建一张过大的贴图,而是增量式的扩大。但是这种方式也存在一个问题,当文本贴图已经创建得很大了,这时候再新增进来一个字符,导致需要重建一张很大的文本贴图,就有可能引起卡顿。所以一些项目组开发的时候往往会在游戏运行的时候先加载进来一批常用字符,来把字体贴图撑大,避免出现配频繁重建的情况。

关于ttf对于不同字号的渲染问题

Alt text Alt text

Alt text Alt text
以上是Text对New Text这段初始化文本在 14 与 24字号的显示下,ttf字体贴图的内容,可以看到24号贴图中有一大一小两份NewTxt的字块贴图。

当需要渲染不同字号的相同文本的时候,ttf字体会为每个字号对应的字符创建一个字块贴图,这些字块贴图会占用整张文本贴图的空间,导致过快得撑满一张贴图,引起扩大重建。这种情况还是很常见的,游戏中很容易就会出现相同的文本在不同的使用场景下,用了不同的字号。这也是提倡不要使用Text组件BestFit功能的一个主要原因,BestFit功能会造成文本字号的不可控,导致创建出许多不同字号的字块贴图。

关于ttf字体可以回滚系统字库的功能

ttf字体的一个优点是可以回滚系统字库,这样不至于出现一些生僻字没有包含在字体中而不能正常渲染的问题。

Alt text
上图来自Unity手册对ttf动态字体功能的说明,除了说了动态字体可以根据输入动态创建字体贴图功能,还说明了动态字体会回滚系统字库的功能。也就是当需要显示的字符没有包含在ttf字体文件中时,Unity会先按照ttf字体 FontNames__字段中设置的回滚字体查找需要的字形,若没有再从用户设备上查找默认字库。这也是为什么Unity内置的Arial字体没有包含中文字符,而使用时却也能正常显示中文的缘故(因为它回滚了系统字库)。

Alt text

关于TextMeshPro字体

关于TextMeshPro的静态与动态字体功能

Alt text
TextMeshPro字体也可以选择静态或动态渲染模式。
选择静态渲染模式则会在游戏运行时就创建一张包含所有字符的贴图,使用动态模式则与ttf的Dynamic类似,在需要的时候动态创建贴图。

Alt text
TextMeshPro字体需要设置一个ttf字体作为字形来源(Source Font File参数),无论是静态或动态渲染模式,字形数据最终都来自于指向的ttf字体。
Sampling Point Size 与 Padding参数
前者是贴图中字块的尺寸,而Padding则是贴图中各字块的间距,当使用描边,阴影等效果的时候会用到。可以通过调节字块尺寸调节字体清晰度,调节padding来调整文字特效的效果,实验下来大概是padding取字块1/10尺寸的时候会得到一个比较好的效果。
Atlas Width 与 Atlas Height两个个参数则是限制了字体贴图的大小,当超过这个尺寸时,就不能再扩展贴图中的字块数量了,也就是新增文字将会被显示为口字。
不过可以通过Multi Atlas Textures参数来解决这个问题,允许创建多张字体贴图,当字体贴图超过尺寸上限,这时又要渲染新的字符时,就会再创建一张字体贴图,新的字符将从该张贴图中获取字块。

关于TextMeshPro的字体回滚功能

Alt text
TextMeshPro字体允许设置一个回滚字体(注意此处的回滚与上面的Dynamic模式回滚ttf模式不同),当本字体中缺少字符时,可以从设置的回滚字体列表(同样都是TextMeshPro字体)中查找需要的字符。
基于这几个特性,使用TextMeshPro可以比较好地解决ttf字体中关于大贴图重建的问题。
可以创建一个包含常用文字的静态字体,并给它设置一个回滚TextMeshPro字体,并将回滚字体设置为动态Dynamic字体,选择一个合适的贴图尺寸(不宜过大,降低重建贴图时的开销),并勾选Multi Atlas Textures参数。

这样,一般使用的时候从静态字体中获取字块,若静态字体中缺少字块时,从动态字体中加载。 可以解决 静态字体字符数过多导致初始加载过大的问题,以及使用动态回滚字体时,重建贴图过大的问题,允许使用多张贴图,将重建一张大贴图的开销拆分到重建小图中。

Alt text
动态创建的贴图会在TextMesh对象子节点中列出。
不过这种做法会导致DrawCall上升,DrawCall数量与贴图数相关。

关于TextMeshPro不能回滚系统字库的问题

ttf字体在渲染字体中不包含的字符时会回滚系统字体,从而不出现无法渲染的情况,而TextMeshPro字体却没有这个特性,即使设置了用于回滚的动态字体,也只能回滚到所指向的ttf中包含的字体,若设置的回滚ttf中也没有包含,那么将会用口字形替代渲染。

这是TextMeshPro目前存在的一个比较大的问题,也正是由于这个,TextMeshPro无法全面替代原生的Text组件,只能用于一些确定性的文本显示,如 标题,章节,任务描述等,而对于由玩家输入的文本,如 聊天,起名等内容,还是只能用Text组件。
所以目前TextMeshPro的现状应该是处于与Text混用的情况,确定性的文本可以用TextMeshPro,非确定性的文本仍旧使用Text。

再记录一些关于TextMesh具体使用的一些操作

关于表情,图文的使用

使用sprite标签显示图片,形如 <sprite=1> 或者 <sprite="Sprite Asset Name" index=1>
第一种方式 需要设置默认图集

Alt text
设置Tmp Setting指定默认图集

Alt text
或者设置TextMesh组件对象绑定默认图集

第二种方式在sprite标签中显示指定图集,用index属性指定图集中的具体小图

关于动态表情使用 anim标签 <sprite=2 anim="2,10,5"> 分别表示首帧,末帧,帧率。

可以通过查看Packages下,TMP_RichTextTagsCommon.cs 文件查看一些标签,属性的使用。

 

— 于 共写了3109个字
— 文内使用到的标签:

2条回应:“关于TextMeshPro”

  1. zhoucy说道:

    关于TextMeshPro不能回滚系统字库的问题
    ———————————————-
    TMPro整合进UGUI后支持Dynamic OS了
    https://docs.unity3d.com/Manual/UIE-font-asset.html

    • 木骰说道:

      这个看起来好像是那个新出的UIToolkit的东西吧。刚看了一下2022的TMP好像还是只能在TMP字体之间回滚。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*