Text 与 TextMeshPro
Text
- Text基于位图的渲染技术
原理
- Text会根据所给定的字符串生成相关的图集,然后对图集进行采样就可以渲染出文字了。文本字形是作为独立的面片(quad)进行渲染的,每个字符都是一个面片。
OnPopulateMesh
(会在Rebuild时调用)- 根据组件的配置生成一个
TextGenerationSettings
,用来生成后面的信息。 - 调用
TextGenerator.PopulateWithErrors
生成 Mesh 的顶点、顶点颜色、UV和三角形信息。 - 计算偏移量(例如左对齐需要紧靠左边),最后遍历
TextGenerator
的顶点数组,将它们的位置除以pixelsPerUnit
(每单元像素)并加上偏移量(如果有的话),得到的结果填到VertexHelper
(可以拿到顶点信息)。
- 根据组件的配置生成一个
字符图集
- 被加载的每个不同的Font对象都会维护自己的纹理集。在Unity的实现中,这些字体在运行时根据Text组件中出现的字符构建一个字形图集(glyph atlas)。
- 动态字体为每种不同的结合(尺寸、样式、字符)在其纹理集中维护了一个字形。也就是说,如果一个UI中有两个Text组件,都显示了字符 “A” ,那么:
- 如果两个Text组件尺寸相同,那么字体图集中会有一个字形。
- 如果两个Text组件尺寸不同,那么字体图集中会有两个不同尺寸的字母 “A” 。
- 如果一个Text组件的样式是粗体而另一个不是,那么字体图集中会含有一个粗体的“A”和一个普通的“A”。
- 当使用动态字体的Text对象遇到了字体纹理集(对应字符图集)中没有的情况,必须重建字体纹理集。
- 如果新的字形能够加入当前图集,那么将其加入图集并上传到图形设备。
- 但是如果当前的图集放不下,那么系统会尝试重建图集。重建图集的过程:
- 尝试回收掉不用的字符。以相同的大小重建图集,只使用当前活动的Text组件上显示的字形。
- 回收后还是放不下就要扩容。例如,一个512x512的图集或被扩充到512x1024的图集。
- 所以,为了避免频繁的重建字符图集,Text使用的字符最好在使用前就填充到字符图集中。
- 如果使用的字体仅需要支持部分字符集(比如只需要几个固定的字),那就可以使用非动态字体并预先配置对想要使用的字体集的支持。
- 字符集不固定或者很多(比如整个Unicode集合),那么字体必须设为动态,可以将出现频率高的字符在游戏运行时填充(使用
Font.RequestCharactersInTexture
)
使用静态字体集
- 待补充
缺点
- 由于使用的是点阵字贴图(贴图存的是颜色值),所以放大缩小文本(更改scale)会使字体编的模糊。
- 前面提到了Text的动态图集是增量式扩大,这种方式在文本量很小的情况下贴图很小,很舒服,但随着文本量的增加,会频繁的发生重建以及扩容,可能会引起卡顿。
- 前面提到了字符图集是按Text组件的设置存储的,所以会出现下面的情况:
- 这些字块贴图会占用整张文本贴图的空间,导致过快的撑满一张贴图,引起扩大重建。而且字号很大的Text所生成的贴图也很大,很占空间,这也是提倡不要使用Text组件
BestFit
功能的一个主要原因,BestFit
功能会造成文本字号的不可控,导致创建出许多不同字号的字块贴图。 - 不支持富文本标签的全部功能、也不支持所有的文本效果,而且一些文本效果实现很不好(描边、阴影等都是通过增加顶点并偏移的方式,正常项目中很少会用到)。
TextMeshPro
- TextMeshPro基于SDF算法(即基于网格的文本渲染技术)。这种实现方式不会出现缩放时的失真并且不会根据不同的字号创建不同的贴图。
SDF算法
- 对于字块,贴图上记录的不是像素的颜色信息,而是每个像素到字形边缘的距离。
- 当文本放大缩小时,TextMeshPro对像素到字形边缘的距离进行插值,而不是对颜色插值,也就是说此处得到的一个字形的轮廓区域,并没有马上得到每个像素的颜色
- 如果用01来表示的话,相当于就是把落在字块上的像素全部标1,然后再进行上色。这样就不存在对颜色插值不准确造成的失真问题,因为对距离的插值总是可以得到一个清晰的字形轮廓。
- 待补充
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 SleepyLoser's Blog!
评论