c++ - 使用翻转正交渲染 FreeType 文本,字形顶部和基线之间的差异

标签 c++ opengl freetype

我正在从事一个项目,我在该项目中实现了一个 FreeType 渲染对象来绘制文本,其渲染环境是使用正交投影矩阵指定的:

glm::ortho(0, Width, Height, 0);

这确保坐标类似于标准 GUI 系统,(0,0) 是窗口的左上部分而不是左下部分。

然而,当使用 FreeType 进行渲染时,事情就变得困难了,因为 FreeType 的原点位于字形的左下角(减去下行部分)。我的问题类似于 https://stackoverflow.com/questions/25353472/render-freetype-gl-text-with-flipped-projection但尚未提供答案,他的解决方案也不合我意(使用的库也略有不同,我假设他使用的是包装器)。

所以我将我的文本呈现如下:

renderText("Testing 123 if text performs sufficiently", 0.0f, 0.0f, 1.0f, 1.0f);

其中renderText函数包含:

renderText(const GLchar *text, GLfloat x, GLfloat y, GLfloat sx, GLfloat sy)
{
    [...]
    GLfloat xpos = x + glyph->bitmap_left * sx; 
    GLfloat ypos = y - glyph->bitmap_top * sy; 
    GLfloat w = glyph->bitmap.width * sx;
    GLfloat h = glyph->bitmap.rows * sy;
    // Update VBO
    GLfloat vertices[4][4] = {
        { xpos,     ypos,       0, 0 },
        { xpos + w, ypos,       1, 0 },
        { xpos,     ypos + h,   0, 1 },
        { xpos + w, ypos + h,   1, 1 }
    };
    [...]
}

如果我这样渲染它,它将在 0 的 y 坐标下方渲染文本,因此除非我向 y 坐标添加偏移量,否则它将不可见。所以看看 FreeType 的字形指标:

glyph metrics from FreeType

我想将 y 位置偏移一个正数,该正数等于字形图像的原点和顶部之间的差值,以便它始终在我给定的位置整齐地呈现文本。查看图像,我相信这是 yMax 值,所以我在更新 VBO 之前将以下语句添加到代码中:

ypos += (glyph->face->bbox.yMax >> 6) * sy; 

当我加载字体大小为 24 的 FreeType 字形时,这似乎解决了这个问题,但是当我尝试使用不同的字体大小时,它就无法正常工作,如下图所示:

font size differences

如您所见,它显然没有像我想象的那样工作。如果我遗漏了什么,我一直在彻底搜索 FreeType 的文档,但我找不到它。我是否使用了错误的指标(使用 Ascender 效果不佳)?

最佳答案

I want to offset the y position by a positive amount equal to the difference between the origin and the top of the glyph image so it always neatly renders the text at my given position. Looking at the image I believe this to be the yMax value so I added the following statement to the code before updating the VBO:

    ypos += (glyph->face->bbox.yMax >> 6) * sy;

实际上,yMax 不是您感兴趣的。您可以使用 yMax - yMin 来查找字形的高度,但仅此而已适合。

来自 FreeType 2 API 文档,FT_GlyphSlotRec::bitmap_top是:

The bitmap's top bearing expressed in integer pixels. Remember that this is the distance from the baseline to the top-most glyph scanline, upwards y coordinates being positive.

再次查看问题中包含的图片,它实际上是 bearingY。你的问题是你在不应该的时候从你的 ypos 中减去这个值。正如我将在下面解释的那样,您确实需要该值,但您绝对不想减去它。

如果从 ypos 的计算中删除 bitmap_top,您将得到以下结果:

False alignment

这显然是不正确的,因为它忽略了字符串中每个字符之间的上升差异。

现在,仔细查看以下正确对齐的图表:

在上图中,我用红色说明了字符串最上面的一行,用绿色说明了最底部的行,用灰色说明了所有字形的基线。

如您所见,大写字母 'T' 的上升幅度最大,这种概括适用于大多数字体。在红线的正下方,我将大写字母 'T' 和当前字母之间的上升差异说明为黄色区域。这是您必须计算以正确对齐字符串的重要数量。

上图中正确对齐的黄色区域可以这样计算:

    Chars['T'].bitmap_top - glyph->bitmap_top

如果您停止从 ypos 中减去 glyph->bitmap_top 并添加上面的值,您应该得到与正确对齐的图表相同的结果。


对于奖励积分,如果你想将你的文本对齐到屏幕的底部,这个概念非常相似,只是你对字符之间的差异感兴趣具有最大血统(通常是小写 'g')和当前字符。这是灰色基线和绿线之间的距离,可以在字形指标图中表示为 height - bearingY

你应该能够使用这个计算下降:

(glyph->metrics.height >> 6) - glyph->bitmap_top // bitmap_top is in integer coords

关于c++ - 使用翻转正交渲染 FreeType 文本,字形顶部和基线之间的差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27469321/

相关文章:

c++ - 这个 C++ 指针容器安全吗?

c++ - C++无法取消引用结束列表迭代器

c++ - 如果使用 va_list 将 args 从可变参数函数传递到另一个函数,如何调用 va_start(无错误)

c++ - Freetype 和 OpenGL 的问题

c++ - Qml:Monospace/Normal 字体的平台独立方式

c++ - 如何在 openGL 中使用 GLFW?

c++ - 通过向方向弯曲来转换线段

c++ - 在 OpenGl 和 OpenFrameworks 中使 3d 模型透明

c - 非常简单的源上的段错误