OpenGL 编程/现代 OpenGL 教程文本渲染 03
你已经阅读了其他两个文本渲染教程,但仍然不满意。你想要全部:对 Unicode 和现代文本整形提供全面支持,在原生 OpenGL 中使用,而无需使用像 Pango 这样的高级库带来的开销和控制权的损失。10 年前,由于封闭标准和固定功能流水线,你将无能为力。今天,这已经触手可及。
在上一个教程中,我们使用了一个带有简单行填充算法的纹理图集。通常我们有一个正方形纹理,例如 2048x2048,所以你应该添加一个简单的检查,当行已满时换行。我们可以使用更复杂的填充算法,但这将是昂贵的计算,我们必须提前知道我们将使用哪些字体和字形。在游戏中,这很容易;我们可以创建多个纹理包,每个包对应一个支持的语言,并在需要时切换它们。
但是,如果你有一个大型字符集,例如阿拉伯语或中文,纹理图集可能会变得有问题。如果你有大量字体,例如在文档处理系统或网页浏览器中,这也是一个问题。网页尤其倾向于使用许多不同的字体和字形,甚至可以使用 WebFonts 动态下载字体。随着字体加载和卸载,不断打包和重新打包我们的字形只会导致更多开销,或者在最坏的情况下,由于我们无法丢弃旧的字形,会导致内存不足错误。
由你决定缓存什么。现在,我们回到第一个教程的简单世界,渲染所有内容,没有任何缓存。
在我们旧的示例中,我们使用了一个简单的计算来进行布局;添加 x 和 y 前进值来获取新的位置。但这根本没有处理连字或非从左到右语言的复杂性。这就是 Harfbuzz 的作用。但是,Harfbuzz 仍然没有处理脚本检测或 Unicode 控制序列;你需要 FriBiDi 或 libraqm 来完成这些操作。但即使是 libraqm 也不处理断行;如果你想要漂亮的换行文本,你将不得不将 minikin 从 Android 的其余部分中分离出来。
无论你使用哪种方法,最终你将获得一个字形列表,以及它们在 x 和 y 坐标上的位置。
字体可以被认为是一堆布局信息加上一系列字形。布局信息由 Harfbuzz 和其他库读取,所以在这里并不特别重要。但是字形很重要。每个字形都是一系列贝塞尔曲线、线段和移动指令。但然后是提示;在典型的字体大小下,大多数字形实际上不会直接绘制轮廓,而是使用专为在低 dpi 下看起来更好的“提示”变体。随着高分辨率“视网膜”显示器的出现,这不再像以前那样是一个问题,但旧显示器仍然存在。
接下来,字形必须被光栅化。你可以用大量的短线段来近似曲线,并直接用 OpenGL 绘制这些线,但这相当昂贵。一个更巧妙的方法是使用 OpenGL 着色器来绘制曲线,但这当然也很棘手,因为它仍然需要三角剖分和细分。幸运的是,这已经在 Glyphy 库中实现了。
最简单的方法是直接在 CPU 上光栅化,通过调用 Freetype 的内置光栅化器。但这很慢,所以无论你使用哪种算法,都需要一个缓存。尤其是阴影,非常昂贵。