我没有使用 OpenGL 方法的选项(即 glxxx()
方法)。我只需要使用 gl 方法绘制文本。看了红皮书才明白,只有通过 glBitmap()
方法才有可能。如果这是唯一可能的方法,那么任何人都可以帮助我了解所有字符的像素阵列信息。有没有其他的方法来绘制文字?
原文由 sathish v 发布,翻译遵循 CC BY-SA 4.0 许可协议
3 回答2k 阅读✓ 已解决
2 回答3.9k 阅读✓ 已解决
2 回答3.2k 阅读✓ 已解决
1 回答3.2k 阅读✓ 已解决
1 回答2.7k 阅读✓ 已解决
3 回答3.4k 阅读
1 回答1.6k 阅读✓ 已解决
理论
为什么难
流行的字体格式如 TrueType 和 OpenType 是矢量轮廓格式:它们使用 贝塞尔曲线 来定义字母的边界。
图片来源。
将这些格式转换为像素数组(光栅化)过于具体且超出了 OpenGL 的范围,特别是因为 OpenGL 没有非直线图元(例如,请参阅 为什么 OpenGL 中没有圆形或椭圆图元? )
最简单的方法是首先在 CPU 上自己光栅字体,然后将像素数组作为纹理提供给 OpenGL。
OpenGL 然后知道如何通过纹理很好地处理像素数组。
纹理图集
我们可以为每一帧光栅字符并重新创建纹理,但这不是很有效,特别是如果字符具有固定大小。
更有效的方法是对您计划使用的所有字符进行光栅化,并将它们填充到单个纹理上。
然后将其传输到 GPU 一次,并使用带有自定义 uv 坐标的纹理来选择正确的角色。
这种方法称为 纹理图集,它不仅可以用于纹理,还可以用于其他重复使用的纹理,例如 2D 游戏中的图块或 Web UI 图标。
完整纹理的维基百科图片本身取自 freetype-gl,很好地说明了这一点:
我怀疑将字符放置优化为最小的纹理问题是一个 NP 难题,请参阅: What algorithm can be used for packing the rectangles into the minimum rectangle possible in a相当优化的方式?
在 web 开发中使用相同的技术来一次传输几个小图像(如图标),但在那里它被称为“CSS Sprites”: https ://css-tricks.com/css-sprites/ 并用于隐藏网络的延迟而不是 CPU / GPU 通信的延迟。
非 CPU 光栅方法
还有一些方法不使用 CPU 光栅来处理纹理。
CPU 光栅化很简单,因为它尽可能少地使用 GPU,但我们也开始考虑是否可以进一步使用 GPU 效率。
此 FOSDEM 2014 视频 解释了其他现有技术:
带有透视的 3D 几何体内部的字体
使用透视渲染 3D 几何体内部的字体(与正交 HUD 相比)要复杂得多,因为透视可以使角色的一部分更靠近屏幕并且比另一部分更大,从而实现统一的 CPU 离散化(例如光栅、镶嵌)在近距离看起来很糟糕。这实际上是一个活跃的研究课题:
从 4.1 版开始,OpenGL 中文本渲染的最新技术是什么?
Valve 20017 年签署的距离场文件。以前在: http ://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf 但公司最终不能不破坏 URL。
https://www.youtube.com/watch?v=1b5hIMqz_wM by Martin Donald (2020) 是一个很好的视频评论,它似乎也提供了一些更具体的使用建议。
距离场 是现在流行的技术之一。
实现
以下示例均在 Ubuntu 15.10 上进行了测试。
因为这是一个前面讨论过的复杂问题,所以大多数示例都很大,并且会破坏此答案的 30k 字符限制,因此只需克隆相应的 Git 存储库进行编译。
然而,它们都是完全开源的,所以你可以只使用 RTFS。
FreeType 解决方案
FreeType 看起来像占主导地位的开源字体光栅化库,因此它允许我们使用 TrueType 和 OpenType 字体,使其成为最优雅的解决方案。
是一组 OpenGL 和 freetype 的示例,但或多或少地演变成一个库,可以做到这一点并公开一个体面的 API。
无论如何,应该已经可以通过复制粘贴一些源代码将其集成到您的项目中。
它提供了开箱即用的纹理图集和距离场技术。
下的演示: https ://github.com/rougier/freetype-gl/tree/master/demos
没有 Debian 软件包,在 Ubuntu 15.10 上编译很痛苦: https ://github.com/rougier/freetype-gl/issues/82#issuecomment-216025527(包装问题,一些上游),但它变得更好截至 16.10。
没有很好的安装方法: https ://github.com/rougier/freetype-gl/issues/115
像这个演示一样生成漂亮的输出:
示例/教程:
其他字体光栅化器
这些似乎不如 FreeType 好,但可能更轻量级:
Anton 的 OpenGL 4 教程示例 26“位图字体”
该字体由作者手动创建并存储在单个
.png
文件中。字母以数组形式存储在图像内。这种方法当然不是很通用,国际化也会有困难。
构建:
输出预览:
opengl-tutorial 第11章“2D字体”
纹理是从 DDS 文件 生成的。
本教程解释了如何使用 CBFG 和 Paint.Net 创建 DDS 文件。
输出预览:
出于某种原因,苏珊娜对我来说不见了,但时间计数器工作正常: https ://github.com/opengl-tutorials/ogl/issues/15
自由GLUT
GLUT有
glutStrokeCharacter
并且FreeGLUT是开源的…… https://github.com/dcnieho/FreeGLUT/blob/FG_3_0_0/src/fg_font.c#L255OpenGL文本
https://github.com/tlorach/OpenGLText
TrueType 栅格。由 NVIDIA 员工提供。旨在实现可重用性。还没试过。
ARM Mali GLES SDK 示例
http://malideveloper.arm.com/resources/sample-code/simple-text-rendering/ 似乎对 PNG 上的所有字符进行编码,并从那里剪切它们。
SDL_ttf
来源: https ://github.com/cirosantilli/cpp-cheat/blob/d36527fe4977bb9ef4b885b1ec92bd0cd3444a98/sdl/ttf.c
与 SDL 位于单独的树中,并且易于集成。
但是不提供纹理图集实现,因此性能将受到限制: 如何使用 SDL2 有效地渲染字体和文本?
相关主题