自版本 4.1 起,OpenGL 中文本渲染的最新技术是什么?

发布于 2024-10-21 09:55:48 字数 1701 浏览 5 评论 0 原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

墨小沫ゞ 2024-10-28 09:55:48

除非您总共只渲染十几个字符,否则渲染轮廓仍然是“不行”的,因为每个字符需要大量顶点来近似曲率。尽管已经有一些方法可以在像素着色器中评估贝塞尔曲线,但这些方法不容易抗锯齿,这对于使用距离贴图纹理四边形来说是微不足道的,并且在着色器中评估曲线在计算上仍然比必要的要昂贵得多。

“快速”和“质量”之间的最佳权衡仍然是具有符号距离场纹理的纹理四边形。它比使用普通普通纹理四边形稍微慢,但也没有慢那么多。另一方面,质量则完全不同。结果确实令人惊叹,速度极快,而且添加发光等效果也非常容易。此外,如果需要,该技术可以很好地降级到较旧的硬件。

有关该技术,请参阅著名的 Valve 论文

该技术在概念上类似于隐式曲面(元球等)的工作原理,尽管它不生成多边形。它完全在像素着色器中运行,将从纹理采样的距离作为距离函数。高于所选阈值(通常为 0.5)的所有内容均为“入”,其他所有内容均为“出”。在最简单的情况下,在已有 10 年历史的不支持着色器的硬件上,将 alpha 测试阈值设置为 0.5 将执行同样的操作(尽管没有特殊效果和抗锯齿功能)。
如果你想给字体增加一点粗细(假粗体),稍微小的阈值就可以做到这一点,而无需修改一行代码(只需更改你的“font_weight”制服)。对于发光效果,人们简单地将高于一个阈值的所有内容视为“进入”,将高于另一个(较小)阈值的所有内容视为“出局,但处于发光状态”,并且 LERP 介于两者之间。抗锯齿的工作原理类似。

通过使用 8 位有符号距离值而不是单个位,该技术将纹理贴图的每个维度的有效分辨率提高了 16 倍(使用所有可能的阴影而不是黑色和白色,因此我们将纹理贴图的有效分辨率提高了 256 倍)。使用相同存储的信息)。但即使放大远远超过 16 倍,结果看起来仍然可以接受。长直线最终会变得有点摇摆,但不会出现典型的“块状”采样伪影。

您可以使用几何着色器来生成点外的四边形(减少总线带宽),但老实说,收益相当有限。 GPG8 中描述的实例化角色渲染也是如此。仅当您有大量文本要绘制时,实例化的开销才会被摊销。在我看来,这些收益与增加的复杂性和不可降级性无关。另外,您要么受到常量寄存器数量的限制,要么必须从纹理缓冲区对象中读取,这对于缓存一致性来说不是最佳的(并且目的是从一开始就进行优化!)。
如果您提前安排上传时间,那么简单、普通的旧顶点缓冲区也同样快(可能更快),并且可以在过去 15 年构建的每个硬件上运行。而且,它不限于字体中的任何特定数量的字符,也不限于要渲染的特定数量的字符。

如果您确定字体中的字符数不超过 256 个,则可能值得考虑使用纹理数组,以与从几何着色器中的点生成四边形类似的方式剥离总线带宽。使用数组纹理时,所有四边形的纹理坐标具有相同的常量 st 坐标,仅在 r 坐标上有所不同,这等于要渲染的字符索引。
但与其他技术一样,预期收益微乎其微,但代价是与上一代硬件不兼容。

Jonathan Dummer 有一个用于生成距离纹理的方便工具:描述页面

更新:
正如最近在可编程顶点拉动(D. Rákos,“OpenGL Insights”,第 239 页)中指出的那样,以编程方式从着色器上拉动顶点数据不会产生显着的额外延迟或开销。最新一代 GPU 与使用标准固定函数执行相同操作相比。
此外,最新一代的 GPU 具有越来越多大小合理的通用 L2 缓存(例如,nvidia Kepler 上的 1536kiB),因此,当从缓冲区纹理中提取四角的随机偏移量时,人们可能会遇到不连贯的访问问题。问题。

这使得从缓冲区纹理中提取恒定数据(例如四边形大小)的想法更具吸引力。因此,假设的实现可以通过如下方法将 PCIe 和内存传输以及 GPU 内存减少到最低限度:

  • 仅上传字符索引(每个要显示的字符一个)作为传递到顶点着色器的唯一输入该索引和gl_VertexID,并将其放大到几何着色器中的4个点,仍然将字符索引和顶点ID(这将是“在顶点着色器中可用的gl_primitiveID”)作为唯一属性,并通过变换反馈捕获这一点。
  • 这会很快,因为只有两个输出属性(GS 中的主要瓶颈),并且在两个阶段都接近“无操作”。
  • 绑定一个缓冲区纹理,其中对于字体中的每个字符,包含纹理四边形相对于基点的顶点位置(这些基本上是“字体度量”)。通过仅存储左下顶点的偏移量,并对轴对齐框的宽度和高度进行编码(假设半浮点,这将是每个字符 8 个字节的常量缓冲区),可以将此数据压缩为每个四边形 4 个数字 -典型的 256 字符字体可以完全放入 2kiB 的 L1 缓存中)。
  • 为基线设置统一 绑定
  • 具有水平偏移的缓冲区纹理。这些甚至甚至可能在 GPU 上计算,但在 CPU 上进行此类操作要容易得多、效率更高,因为它是一个严格的顺序操作,而且一点也不简单(想想字距调整) )。此外,它还需要另一个反馈通道,这将是另一个同步点。
  • 从反馈缓冲区渲染先前生成的数据,顶点着色器从缓冲区对象中拉出基点的水平偏移量和角顶点的偏移量(使用图元 id 和字符索引)。提交的顶点的原始顶点ID现在是我们的“原始ID”(记住GS将顶点变成了四边形)。

像这样,理想情况下可以将所需的顶点带宽减少 75%(摊销),尽管它只能渲染一条线。如果希望能够在一次绘制调用中渲染多条线,则需要将基线添加到缓冲区纹理,而不是使用统一的(使带宽增益更小)。

然而,即使假设减少 75%,因为显示“合理”数量的文本的顶点数据仅为 50-100kiB 左右(对于 GPU 或 PCIe 总线来说,这几乎)- - 我仍然怀疑增加的复杂性和失去向后兼容性是否真的值得这么麻烦。将零减少75%仍然只是零。诚然,我没有尝试过上述方法,需要更多的研究才能做出真正合格的声明。但是,除非有人能够证明真正令人惊叹的性能差异(使用“正常”数量的文本,而不是数十亿个字符!),否则我的观点仍然是,对于顶点数据,一个简单、普通的旧顶点缓冲区就足够好了被视为“最先进的解决方案”的一部分。它简单明了,有效,而且效果很好。

上面已经引用了“OpenGL Insights”,还值得指出“2D 形状渲染”一章Stefan Gustavson 的《距离场》,其中详细解释了距离场渲染。

2016 年更新

同时,还存在多种附加技术,旨在消除在极端放大倍数下会产生干扰的圆角伪影。

一种方法简单地使用伪距离场而不是距离场(区别在于,距离不是到实际轮廓的最短距离,而是到轮廓或突出于边缘的假想线的最短距离)。这稍微好一些,并且以相同的速度运行(相同的着色器),使用相同数量的纹理内存。

另一种方法在三通道纹理细节和实现中使用三中位数,可在 github 上找到。其目的是对之前用于解决该问题的和/或黑客进行改进。质量好,稍微慢一点,几乎不明显,但使用三倍的纹理内存。此外,额外的效果(例如发光)更难实现。

最后,存储构成字符的实际贝塞尔曲线,并在片段着色器中对其进行评估 已经变得实用,性能稍差(但还没有严重到成为问题),即使在最高放大倍数下也能获得令人惊叹的结果。
此处提供了使用此技术实时渲染大型 PDF 的 WebGL 演示。

Rendering outlines, unless you render only a dozen characters total, remains a "no go" due to the number of vertices needed per character to approximate curvature. Though there have been approaches to evaluate bezier curves in the pixel shader instead, these suffer from not being easily antialiased, which is trivial using a distance-map-textured quad, and evaluating curves in the shader is still computationally much more expensive than necessary.

The best trade-off between "fast" and "quality" are still textured quads with a signed distance field texture. It is very slightly slower than using a plain normal textured quad, but not so much. The quality on the other hand, is in an entirely different ballpark. The results are truly stunning, it is as fast as you can get, and effects such as glow are trivially easy to add, too. Also, the technique can be downgraded nicely to older hardware, if needed.

See the famous Valve paper for the technique.

The technique is conceptually similar to how implicit surfaces (metaballs and such) work, though it does not generate polygons. It runs entirely in the pixel shader and takes the distance sampled from the texture as a distance function. Everything above a chosen threshold (usually 0.5) is "in", everything else is "out". In the simplest case, on 10 year old non-shader-capable hardware, setting the alpha test threshold to 0.5 will do that exact thing (though without special effects and antialiasing).
If one wants to add a little more weight to the font (faux bold), a slightly smaller threshold will do the trick without modifying a single line of code (just change your "font_weight" uniform). For a glow effect, one simply considers everything above one threshold as "in" and everything above another (smaller) threshold as "out, but in glow", and LERPs between the two. Antialiasing works similarly.

By using an 8-bit signed distance value rather than a single bit, this technique increases the effective resolution of your texture map 16-fold in each dimension (instead of black and white, all possible shades are used, thus we have 256 times the information using the same storage). But even if you magnify far beyond 16x, the result still looks quite acceptable. Long straight lines will eventually become a bit wiggly, but there will be no typical "blocky" sampling artefacts.

You can use a geometry shader for generating the quads out of points (reduce bus bandwidth), but honestly the gains are rather marginal. The same is true for instanced character rendering as described in GPG8. The overhead of instancing is only amortized if you have a lot of text to draw. The gains are, in my opinion, in no relation to the added complexity and non-downgradeability. Plus, you are either limited by the amount of constant registers, or you have to read from a texture buffer object, which is non-optimal for cache coherence (and the intent was to optimize to begin with!).
A simple, plain old vertex buffer is just as fast (possibly faster) if you schedule the upload a bit ahead in time and will run on every hardware built during the last 15 years. And, it is not limited to any particular number of characters in your font, nor to a particular number of characters to render.

If you are sure that you do not have more than 256 characters in your font, texture arrays may be worth a consideration to strip off bus bandwidth in a similar manner as generating quads from points in the geometry shader. When using an array texture, the texture coordinates of all quads have identical, constant s and t coordinates and only differ in the r coordinate, which is equal to the character index to render.
But like with the other techniques, the expected gains are marginal at the cost of being incompatible with previous generation hardware.

There is a handy tool by Jonathan Dummer for generating distance textures: description page

Update:
As more recently pointed out in Programmable Vertex Pulling (D. Rákos, "OpenGL Insights", pp. 239), there is no significant extra latency or overhead associated with pulling vertex data programmatically from the shader on the newest generations of GPUs, as compared to doing the same using the standard fixed function.
Also, the latest generations of GPUs have more and more reasonably sized general-purpose L2 caches (e.g. 1536kiB on nvidia Kepler), so one may expect the incoherent access problem when pulling random offsets for the quad corners from a buffer texture being less of a problem.

This makes the idea of pulling constant data (such as quad sizes) from a buffer texture more attractive. A hypothetical implementation could thus reduce PCIe and memory transfers, as well as GPU memory, to a minimum with an approach like this:

  • Only upload a character index (one per character to be displayed) as the only input to a vertex shader that passes on this index and gl_VertexID, and amplify that to 4 points in the geometry shader, still having the character index and the vertex id (this will be "gl_primitiveID made available in the vertex shader") as the sole attributes, and capture this via transform feedback.
  • This will be fast, because there are only two output attributes (main bottleneck in GS), and it is close to "no-op" otherwise in both stages.
  • Bind a buffer texture which contains, for each character in the font, the textured quad's vertex positions relative to the base point (these are basically the "font metrics"). This data can be compressed to 4 numbers per quad by storing only the offset of the bottom left vertex, and encoding the width and height of the axis-aligned box (assuming half floats, this will be 8 bytes of constant buffer per character -- a typical 256 character font could fit completely into 2kiB of L1 cache).
  • Set an uniform for the baseline
  • Bind a buffer texture with horizontal offsets. These could probably even be calculated on the GPU, but it is much easier and more efficient to that kind of thing on the CPU, as it is a strictly sequential operation and not at all trivial (think of kerning). Also, it would need another feedback pass, which would be another sync point.
  • Render the previously generated data from the feedback buffer, the vertex shader pulls the horizontal offset of the base point and the offsets of the corner vertices from buffer objects (using the primitive id and the character index). The original vertex ID of the submitted vertices is now our "primitive ID" (remember the GS turned the vertices into quads).

Like this, one could ideally reduce the required vertex bandwith by 75% (amortized), though it would only be able to render a single line. If one wanted to be able to render several lines in one draw call, one would need to add the baseline to the buffer texture, rather than using an uniform (making the bandwidth gains smaller).

However, even assuming a 75% reduction -- since the vertex data to display "reasonable" amounts of text is only somewhere around 50-100kiB (which is practically zero to a GPU or a PCIe bus) -- I still doubt that the added complexity and losing backwards-compatibility is really worth the trouble. Reducing zero by 75% is still only zero. I have admittedly not tried the above approach, and more research would be needed to make a truly qualified statement. But still, unless someone can demonstrate a truly stunning performance difference (using "normal" amounts of text, not billions of characters!), my point of view remains that for the vertex data, a simple, plain old vertex buffer is justifiably good enough to be considered part of a "state of the art solution". It's simple and straightforward, it works, and it works well.

Having already referenced "OpenGL Insights" above, it is worth to also point out the chapter "2D Shape Rendering by Distance Fields" by Stefan Gustavson which explains distance field rendering in great detail.

Update 2016:

Meanwhile, there exist several additional techniques which aim to remove the corner rounding artefacts which become disturbing at extreme magnifications.

One approach simply uses pseudo-distance fields instead of distance fields (the difference being that the distance is the shortest distance not to the actual outline, but to the outline or an imaginary line protruding over the edge). This is somewhat better, and runs at the same speed (identical shader), using the same amount of texture memory.

Another approach uses the median-of-three in a three-channel texture details and implementation available at github. This aims to be an improvement over the and-or hacks used previously to address the issue. Good quality, slightly, almost not noticeably, slower, but uses three times as much texture memory. Also, extra effects (e.g. glow) are harder to get right.

Lastly, storing the actual bezier curves making up characters, and evaluating them in a fragment shader has become practical, with slightly inferior performance (but not so much that it's a problem) and stunning results even at highest magnifications.
WebGL demo rendering a large PDF with this technique in real time available here.

半寸时光 2024-10-28 09:55:48

http://code.google.com/p/glyphy/

GLyphy 和其他基于 SDF 的 OpenGL 渲染器之间的主要区别在于大多数其他项目将 SDF 采样到纹理中。这具有采样所具有的所有常见问题。 IE。它会扭曲轮廓并且质量低下。 GLyphy 使用提交给 GPU 的实际向量来表示 SDF。这会产生非常高质量的渲染。

缺点是该代码适用于带有 OpenGL ES 的 iOS。我可能会制作一个 Windows/Linux OpenGL 4.x 端口(不过希望作者能添加一些真实的文档)。

http://code.google.com/p/glyphy/

The main difference between GLyphy and other SDF-based OpenGL renderers is that most other projects sample the SDF into a texture. This has all the usual problems that sampling has. Ie. it distorts the outline and is low quality. GLyphy instead represents the SDF using actual vectors submitted to the GPU. This results in very high quality rendering.

The downside is that the code is for iOS with OpenGL ES. I'm probably going to make a Windows/Linux OpenGL 4.x port (hopefully the author will add some real documentation, though).

鹿港巷口少年归 2024-10-28 09:55:48

最广泛使用的技术仍然是纹理四边形。然而,在 2005 年,LORIA 开发了一种称为矢量纹理的东西,即将矢量图形渲染为图元上的纹理。如果使用它将 TrueType 或 OpenType 字体转换为矢量纹理,您会得到以下结果:

http: //alice.loria.fr/index.php/publications.html?Paper=VTM@2005

The most widespread technique is still textured quads. However in 2005 LORIA developed something called vector textures, i.e. rendering vector graphics as textures on primitives. If one uses this to convert TrueType or OpenType fonts into a vector texture you get this:

http://alice.loria.fr/index.php/publications.html?Paper=VTM@2005

何时共饮酒 2024-10-28 09:55:48

我很惊讶马克·基尔加德的孩子 NV_path_rendering (NVpr) 没有被上述提及。尽管它的目标比字体渲染更通用,但它也可以通过字体和字距调整来渲染文本。它甚至不需要 OpenGL 4.1,但目前它只是供应商/Nvidia 的扩展。它基本上使用 glPathGlyphsNV 将字体转换为路径,这依赖于 freetype2 库来获取指标等。然后您还可以使用 glGetPathSpacingNV 访问字距调整信息并使用 NVpr 的通用路径使用路径“转换”字体显示文本的呈现机制。 (我把它放在引号中,因为没有真正的转换,曲线按原样使用。)

记录的 不幸的是,NVpr 字体功能的演示并不是特别令人印象深刻。 (也许有人应该按照更时尚的 SDF 演示制作一个,可以在intertubes...)

2011 年 NVpr API 字体部分演示演讲 从这里开始< /a> 并继续下一部分;该演示文稿的分割方式有点不幸。

有关 NVpr 的更多一般材料:

  • Nvidia NVpr hub,但登陆页面上的某些材料不是最新的
  • Siggraph 2012 论文 路径渲染方法的大脑,称为“模板,然后覆盖”(StC);该论文还简要解释了 Direct2D 等竞争技术的工作原理。与字体相关的位已被降级为附件纸。还有一些额外内容,例如视频/演示
  • GTC 2014 演示文稿获取更新状态;简而言之:它现在得到了 Google 的 Skia 的支持(Nvidia 在 2013 年末和 2014 年贡献了代码),而后者又被用于 Google Chrome 和 [独立于 Skia,我认为] Adob​​e Illustrator CC 2014 的测试版中
  • OpenGL 扩展注册表中的官方文档
  • USPTO 已向 Kilgard 授予了至少四项专利/ Nvidia 与 NVpr 的关系,如果您想自己实现 StC,您可能应该了解这一点: US8698837US8698808US8704830US8730253。请注意,还有 17 份与此相关的 USPTO 文件“也发布为”,其中大部分是专利申请,因此完全有可能从这些文件中授予更多专利。

由于在我回答之前,“stencil”这个词在这个页面上没有产生任何点击,看来参与这个页面的 SO 社区的子集,尽管数量相当多,但并不知道无曲面细分、模板缓冲区 -一般而言,基于路径/字体渲染的方法。 Kilgard 有一个 opengl 论坛上类似常见问题解答的帖子 可能会说明无曲面细分路径渲染方法与标准 3D 图形有何不同,即使它们仍在使用 [GP]GPU。 (NVpr 需要支持 CUDA 的芯片。)

从历史角度来看,Kilgard 也是经典 “用于纹理映射文本的基于 OpenGL 的简单 API”,SGI,1997,不应将其与 2011 年首次推出的基于模板的 NVpr 相混淆。


大多数(如果不是全部)最近的本页讨论的方法,包括基于模板的方法,如 NVpr 或基于 SDF 的方法,如 GLyphy(我不再在这里进一步讨论,因为其他答案已经涵盖它),但有一个限制:它们适合在传统(~100 DPI)显示器在任何缩放级别都没有锯齿,而且即使尺寸很小,在高 DPI、类视网膜显示屏上它们也看起来不错。然而,它们并没有完全提供 Microsoft 的 Direct2D+DirectWrite 所提供的功能,即在主流显示器上提示小字形。 (有关一般提示的视觉调查,请参阅此打字页面例如。更深入的 位于 antigrain.com。)

资源 产品化的基于 OpenGL 的东西,可以做到微软目前可以通过暗示做到的事情。 (我承认对 Apple 的 OS X GL/Quartz 内部结构一无所知,因为据我所知,Apple 尚未发布他们如何进行基于 GL 的字体/路径渲染内容。似乎 OS X 与 MacOS 9 不同,没有发布做任何暗示,这会惹恼一些人.) 无论如何,有一篇 2013 年的研究论文讨论了通过 OpenGL 着色器进行提示作者:INRIA 的 Nicolas P. Rougier;如果您需要从 OpenGL 进行提示,那么它可能值得一读。虽然看起来像 freetype 这样的库已经完成了提示方面的所有工作,但实际上并非如此,原因如下,我从论文中引用了这一点:

FreeType 库可以在 RGB 模式下使用子像素抗锯齿来栅格化字形。
然而,这只是问题的一半,因为我们还想实现亚像素
定位以准确放置字形。显示纹理四边形
分数像素坐标并不能解决问题,因为它只会产生纹理
全像素级别的插值。相反,我们想要实现精确的转变
(0 和 1 之间)在子像素域中。这可以在片段着色器中完成[...]。

该解决方案并不完全是微不足道的,因此我不打算在这里尝试解释它。 (这篇论文是开放获取的。)


我从 Rougier 的论文中学到的另一件事(Kilgard 似乎没有考虑到这一点)是,字体的力量(Microsoft+Adobe)创造的不是一种而是两种字距调整规范方法。旧的基于所谓的kern表,并且受freetype支持。新的字体库称为 GPOS,它仅受自由软件世界中较新的字体库(例如 HarfBuzz 或 pango)的支持。由于 NVpr 似乎不支持这两个库,因此对于某些新字体,NVpr 的字距调整可能无法开箱即用;根据此论坛讨论,其中一些显然是在野外

最后,如果您需要执行复杂文本布局(CTL),那么您目前似乎不走运使用 OpenGL,因为似乎不存在基于 OpenGL 的库。 (另一方面 DirectWrite 可以处理 CTL。)有像 HarfBuzz 这样的开源库可以渲染 CTL,但我不知道如何让它们很好地工作(如使用基于模板的方法) OpenGL。您可能必须编写粘合代码来提取重新塑造的轮廓并将其作为路径输入到基于 NVpr 或 SDF 的解决方案中。

I'm surprised Mark Kilgard's baby, NV_path_rendering (NVpr), was not mentioned by any of the above. Although its goals are more general than font rendering, it can also render text from fonts and with kerning. It doesn't even require OpenGL 4.1, but it is a vendor/Nvidia-only extension at the moment. It basically turns fonts into paths using glPathGlyphsNV which depends on the freetype2 library to get the metrics, etc. Then you can also access the kerning info with glGetPathSpacingNV and use NVpr's general path rendering mechanism to display text from using the path-"converted" fonts. (I put that in quotes, because there's no real conversion, the curves are used as is.)

The recorded demo for NVpr's font capabilities is unfortunately not particularly impressive. (Maybe someone should make one along the lines of the much snazzier SDF demo one can find on the intertubes...)

The 2011 NVpr API presentation talk for the fonts part starts here and continues in the next part; it is a bit unfortunate how that presentation is split.

More general materials on NVpr:

  • Nvidia NVpr hub, but some material on the landing page is not the most up-to-date
  • Siggraph 2012 paper for the brains of the path-rendering method, called "stencil, then cover" (StC); the paper also explains briefly how competing tech like Direct2D works. The font-related bits have been relegated to an annex of the paper. There are also some extras like videos/demos.
  • GTC 2014 presentation for an update status; in a nutshell: it's now supported by Google's Skia (Nvidia contributed the code in late 2013 and 2014), which in turn is used in Google Chrome and [independently of Skia, I think] in a beta of Adobe Illustrator CC 2014
  • the official documentation in the OpenGL extension registry
  • USPTO has granted at least four patents to Kilgard/Nvidia in connection with NVpr, of which you should probably be aware of, in case you want to implement StC by yourself: US8698837, US8698808, US8704830 and US8730253. Note that there are something like 17 more USPTO documents connected to this as "also published as", most of which are patent applications, so it's entirely possible more patents may be granted from those.

And since the word "stencil" did not produce any hits on this page before my answer, it appears the subset of the SO community that participated on this page insofar, despite being pretty numerous, was unaware of tessellation-free, stencil-buffer-based methods for path/font rendering in general. Kilgard has a FAQ-like post at on the opengl forum which may illuminate how the tessellation-free path rendering methods differ from bog standard 3D graphics, even though they're still using a [GP]GPU. (NVpr needs a CUDA-capable chip.)

For historical perspective, Kilgard is also the author of the classic "A Simple OpenGL-based API for Texture Mapped Text", SGI, 1997, which should not be confused with the stencil-based NVpr that debuted in 2011.


Most if not all the recent methods discussed on this page, including stencil-based methods like NVpr or SDF-based methods like GLyphy (which I'm not discussing here any further because other answers already cover it) have however one limitation: they are suitable for large text display on conventional (~100 DPI) monitors without jaggies at any level of scaling, and they also look nice, even at small size, on high-DPI, retina-like displays. They don't fully provide what Microsoft's Direct2D+DirectWrite gives you however, namely hinting of small glyphs on mainstream displays. (For a visual survey of hinting in general see this typotheque page for instance. A more in-depth resource is on antigrain.com.)

I'm not aware of any open & productized OpenGL-based stuff that can do what Microsoft can with hinting at the moment. (I admit ignorance to Apple's OS X GL/Quartz internals, because to the best of my knowledge Apple hasn't published how they do GL-based font/path rendering stuff. It seems that OS X, unlike MacOS 9, doesn't do hinting at all, which annoys some people.) Anyway, there is one 2013 research paper that addresses hinting via OpenGL shaders written by INRIA's Nicolas P. Rougier; it is probably worth reading if you need to do hinting from OpenGL. While it may seem that a library like freetype already does all the work when it comes to hinting, that's not actually so for the following reason, which I'm quoting from the paper:

The FreeType library can rasterize a glyph using sub-pixel anti-aliasing in RGB mode.
However, this is only half of the problem, since we also want to achieve sub-pixel
positioning for accurate placement of the glyphs. Displaying the textured quad at
fractional pixel coordinates does not solve the problem, since it only results in texture
interpolation at the whole-pixel level. Instead, we want to achieve a precise shift
(between 0 and 1) in the subpixel domain. This can be done in a fragment shader [...].

The solution is not exactly trivial, so I'm not going to try to explain it here. (The paper is open-access.)


One other thing I've learned from Rougier's paper (and which Kilgard doesn't seem to have considered) is that the font powers that be (Microsoft+Adobe) have created not one but two kerning specification methods. The old one is based on a so-called kern table and it is supported by freetype. The new one is called GPOS and it is only supported by newer font libraries like HarfBuzz or pango in the free software world. Since NVpr doesn't seem to support either of those libraries, kerning might not work out of the box with NVpr for some new fonts; there are some of those apparently in the wild, according to this forum discussion.

Finally, if you need to do complex text layout (CTL) you seem to be currently out of luck with OpenGL as no OpenGL-based library appears to exist for that. (DirectWrite on the other hand can handle CTL.) There are open-sourced libraries like HarfBuzz which can render CTL, but I don't know how you'd get them to work well (as in using the stencil-based methods) via OpenGL. You'd probably have to write the glue code to extract the re-shaped outlines and feed them into NVpr or SDF-based solutions as paths.

豆芽 2024-10-28 09:55:48

我认为你最好的选择是研究带有 OpenGL 后端的 cairo Graphics

我在开发 3.3 核心原型时遇到的唯一问题是 OpenGL 后端中不推荐使用的函数。那是一两年前的事了,所以情况可能有所改善……

无论如何,我希望将来的桌面 opengl 图形驱动程序能够实现 OpenVG。

I think your best bet would be to look into cairo graphics with OpenGL backend.

The only problem I had when developing a prototype with 3.3 core was deprecated function usage in OpenGL backend. It was 1-2 years ago so situation might have improved...

Anyway, I hope in the future desktop opengl graphics drivers will implement OpenVG.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文