40

我正在实现一个基于 OpenGL 的 GUI。我遇到了每个 GUI 都会遇到的问题——文本渲染。我知道在 OpenGL 中呈现文本的几种方法,但是,我想知道哪种方法最适合 GUI。

通常在 GUI 中我们有两种类型的文本——静态的和实时的。静态很容易——我们可以将一个 TTF 渲染到一个纹理上然后忘记它。更让我困扰的是“实时”文本——想象一下控制台,或者多人游戏中的实时聊天。

我想到了几个选择:

  • 没有特殊情况 - 每次文本更改时渲染和加载纹理,请记住仅在实际出现新文本时重新渲染它,并尝试将较大的文本分成小部分(如每个聊天行)。然而,这仍然会让我们陷入困境,比如一直在变化的分数线,或者呈现“每个字符”的介绍文本(在某些科幻游戏中看到的打字机风格)
  • 四字符 - 这似乎也是一个流行的解决方案,您使用 ASCII 表准备纹理并渲染纹理四字符。但是,我严重怀疑这种解决方案的效率。如何加快速度的提示也将受到欢迎。
  • 混合解决方案——但是我不知道如何干净地实现它

因此问题是——如何有效地在 OpenGL 中渲染文本?

如果这有帮助,我正在使用 STL/Boost-heavy C++ 进行编码,并针对 GForce 6 及更高版本的显卡。

4

7 回答 7

30

EDIT2:Sean Barrett 刚刚为 C/C++ 3D 程序员发布了位图字体

编辑:另一个值得一看的代码宝石是Font Stash,它利用了 Sean Barrett 的stb_truetype.h


您可以创建一个纹理,在其中渲染字体的所有字符。然后,您只需使用正交投影和适当的纹理坐标绘制纹理四边形:当您的文本使用不包含太多符号的语言时,这种方法适用:比如英语。字体纹理在应用程序开始时创建一次,然后渲染四边形非常快。

这就是我正在使用的,我相信这是在 OpenGL 中呈现文本的最快方式。起初,我使用了 Angelcode 的 Bitmap Font Generator工具,然后我直接集成了FreeType,并在应用程序启动时构建了一个包含所有字形的大纹理。至于提高四边形渲染速度的技巧,我只是将 VBO 用于我应用程序中的其余几何体。

我很惊讶您对四边形渲染有疑问,而您似乎并不担心在 cpu 上生成纹理,然后上传它,然后绑定它以最终用它渲染一个矩形的性能,即每一帧。更改 OpenGL 状态是瓶颈,而不是用于文本的 500 - 1000 个四边形。

另外,请查看诸如FTGL库之类的库,该库将整个字体转换为多边形(几何字体)。

于 2010-01-15T13:20:31.840 回答
8

尝试阅读:http ://dmedia.dprogramming.com/?n=Tutorials.TextRendering1 。

所描述的方法是使用图形 API 进行文本渲染的典型方法。每个四边形一个字符,以及单个纹理中文本的所有图像数据。如果您可以将整个字符集放入一个纹理中(实际上,取决于纹理的大小,您可能可以容纳多个),则渲染速度非常快。

关键是纹理绑定是你需要最小化的操作。如果您可以使用单个纹理渲染所有文本,那么您需要在屏幕上放置多少文本都无关紧要。即使您必须多次切换纹理(不同的字体、不同的字体属性 [粗体、下划线等]),性能仍然应该不错。文本性能对于 HUD 可能更为关键,但在 GUI 中则不那么重要。

于 2010-01-15T13:47:12.910 回答
5

您可以将文本渲染为三角面,并避免使用纹理。这样可以在文本缩放时避免边缘不清晰。我创作了一种低多边形 ASCII 字体,它是开源的,可在我的 github 上找到。

另一种在文本上具有锐利边缘的方法是SDF 字体渲染,但这会受到一些伪影的影响。

于 2015-03-07T03:53:11.890 回答
1

这很棘手,特别是如果您想使用亚像素字体渲染技术。看看ClanLib SDK。它使用批处理渲染器在单个 OpenGL 调用中渲染整个屏幕的文本。由于它具有基于 zlib 的许可证,如果您不想使用 SDK 本身,可以提取其代码

于 2013-09-25T09:49:47.790 回答
1

可以只使用这两个功能:

void renderstring2d(char string[], float r, float g, float b, float x, float y)
{
    glColor3f(r, g, b);

    glRasterPos2f(x, y);
    for(unsigned int i = 0; i < strlen(string); i++)
        glutBitmapCharacter(GLUT_BITMAP_9_BY_15, string[i]);
}

void renderstring3d(char string[], float r, float g, float b, float x, float y, float z)
{
    glDisable(GL_LIGHTING);
    glColor3f(r, g, b);

    glRasterPos3f(x, y, z);
    for(unsigned int i = 0; i < strlen(string); i++)
        glutBitmapCharacter(GLUT_BITMAP_9_BY_15, string[i]);
}

然后在渲染 2D 文本时,不要忘记重置模型视图和投影矩阵。

glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();

// Render text and quads

glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();

您不需要使用这些函数渲染到四边形,因为这些函数直接渲染到帧缓冲区。

如果这对您不起作用,请检查一下。 http://www.opengl.org/resources/faq/technical/fonts.htm

它讨论了使用 glBitmap、glDrawPixels 和 alpha 混合渲染文本。

于 2010-01-15T14:15:09.983 回答
1

对于大多数情况,每个四字符处理认为显示列表(仅在文本更改时更新)就足够了。

我使用 XLoadQueryFont、glGenLists、glXUseXFont、glCallLists 将它与 X11 字体一起使用,您有一个描述每个字符的显示列表数组。

glCallLists 函数接受文本的 char * 参数,它可以嵌入显示列表中。

因此,您最终只需一次调用即可显示块文本。

G. Pakosz 建议的字体纹理是类似的,但是您可以计算自己的“按字符”显示列表。

您的第一个选项会很慢,因为它需要在每次文本更改时进行基于处理器的渲染。

于 2010-01-15T13:48:46.640 回答