osg 使用整理 (9):文本渲染

发布时间 2023-10-29 22:30:23作者: 王小于的啦

osg 使用整理 (9):文本渲染

1 FreeType文本渲染

​ FreeType用于加载TrueType字体并渲染到位图的库。TrueType字体通过数学公式表示的曲线来描述字体轮廓。类似于矢量图像,这些光栅化后的字体图像可以根据需要的字体高度来生成。FreeType所做的事就是加载TrueType字体并为每一个字形生成位图以及计算几个度量值(Metric)。我们可以提取出它生成的位图作为字形的纹理,并使用这些度量值定位字符的字形。

​ a. 初始化FreeType库,并且将这个字体加载为一个FreeType称为面的东西。

​ b. 定义字体大小,设置字体宽度高度。

​ c. 调用FT_Load_Char函数激活指定的字形。调用FT_LOAD_RENDER创建8位灰度位图。

​ 使用FreeType加载的每个字形没有相同的大小。使用FreeType生成的位图大小恰好能包含这个字符可见区域。因此FreeType加载了一些度量值来指定每个字符的大小和位置。如下图所示。
每一个字形都放在一个水平的基准线上。一些字形恰好位于基准线上,而另外一些则会稍微越过基准线以下。这些度量值精确定义了摆放字形所需的每个字形距离基准线的偏移量、每个字形的大小、预留空间大小。可以定义一个结构体存储字形对应的度量值以及纹理。

2 osg::TextBase类

​ osgText库中实现了二维、三维文本渲染,可以自由设置参数达到不同的渲染效果。字体基类的成员变量和成员函数如下图所示。

常用属性设置接口:

设置文字分辨率
void setFontResolution(unsigned int width,unsigned int height) 默认为32*32个像素单元
设置对齐方式
void setAlignment(Alignment alignment)
设置布局方式
void setLayout(Layout layout)
设置绘制模式
void setDrawMode(unsigned int mode)

​ 实现逻辑:

a. 创建一个Font字体对象,并读取字体。调用FreeType遍历字符生成每个字符的纹理和字符度量值。

b. 创建一个osgText::Text对象,设置文字属性,同时关联字体。遍历一行字符串渲染每一个字符,我们从之前创建的Characters映射表中取出对应的Character结构体,并根据字符的度量值来计算四边形的维度。根据四边形的维度我们就能动态计算出6个描述四边形的顶点,并使用glBufferSubData函数更新VBO所管理内存的内容。

c. 实现shader

#version 330 core
layout (location = 0) in vec4 vertex; // <vec2 pos, vec2 tex>
out vec2 TexCoords;

uniform mat4 projection;

void main()
{
    gl_Position = projection * vec4(vertex.xy, 0.0, 1.0);
    TexCoords = vertex.zw;
}
#version 330 core
in vec2 TexCoords;
out vec4 color;

uniform sampler2D text;
uniform vec3 textColor;

void main()
{    
    vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);
    color = vec4(textColor, 1.0) * sampled;
}

3 SDF渲染字体技术

​ 流程

​ a. TTF将矢量字库中的字符,按照要求的尺寸输出为灰度点阵图,在这一过程中字库引擎处理了AA以及像素匹配

​ b. 将字符灰度点阵图写入到字符图集纹理中,并记录其对应的uv位置和尺寸

​ c. 计算字符面片的顶点位置,要保证其在像素中间,大小与字符图元一致,以得到最好的渲染效果

​ d. 纹理、材质、模型传给GPU进行渲染