从4.1版开始,OpenGL中的文本呈现技术是什么?[关闭]


199

关于OpenGL中的文本渲染,已经存在许多问题,例如:

但主要讨论的是使用固定功能管线渲染带纹理的四边形。当然,着色器必须提供更好的方法。

我并不真正在意国际化,我的大多数字符串都将是图形刻度标签(日期和时间或纯数字)。但是这些图将以屏幕刷新率重新渲染,并且可能会有很多文本(屏幕上不超过几千个字形,但足以使硬件加速的布局就不错了)。

使用现代OpenGL进行文本渲染的推荐方法是什么?(使用该方法引用现有软件是很好的证据,证明它运行良好)

  • 几何着色器,接受例如位置和方向以及字符序列,并发出带纹理的四边形
  • 渲染矢量字体的几何着色器
  • 如上,但是使用镶嵌着色器代替
  • 计算着色器以进行字体光栅化

10
我无法回答当前的问题,主要是面向OpenGL ES,但是我使用GLU镶嵌器对TTF进行了细分,并通过旧的固定功能管道将其提交为几何图形,并在CPU上计算了字距调整,从而在反抗方面获得了良好的视觉效果。 -几乎在十年前全面实现了硬件混叠和良好的性能。因此,不仅可以通过着色器找到“更好”的方式(当然,这取决于您的标准)。FreeType可以吐出Bezier字形边界和字距调整信息,因此您可以在运行时通过TTF进行实时工作。
汤米

(Qt5的)QML2在呈现文本时使用OpenGL和距离字段做了一些有趣的技巧:blog.qt.digia.com/blog/2012/08/08/native-looking-text-in-qml-2
mlvljr

因此,我不会再失去它,这里是一个实现Valve距离场方法的库。code.google.com/p/glyphy我还没有尝试过。也可能值得一看:code.google.com/p/signed-distance-field-font-generator
Timmmm 2014年

7
这种“离题”是堆栈溢出的诅咒。认真吗?
Nikolaos Giotis 2014年

Answers:


202

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

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

有关该技术,请参见著名的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个字符的字体可能完全适合L1缓存的2kiB)。
  • 为基准设置统一
  • 将缓冲区纹理与水平偏移绑定。这些可能甚至可能在GPU上进行计算,但它更容易和更高效的那种事的CPU上,因为这是一个严格的顺序操作,而不是在所有的琐碎(认为字距的)。同样,它将需要另一个反馈传递,这将是另一个同步点。
  • 渲染先前从反馈缓冲区生成的数据,顶点着色器从缓冲区对象中提取基点的水平偏移和角顶点的偏移(使用原始ID和字符索引)。现在,提交的顶点的原始顶点ID是我们的“原始ID”(请记住,GS将这些顶点变成了四边形)。

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

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

在上面已经提到了“ OpenGL见解 ”之后,还值得一提的是Stefan Gustavson撰写的通过距离场进行2D形状渲染”一章,其中详细介绍了距离场渲染。

2016年更新:

同时,存在一些附加技术,其目的是消除在极端放大倍率下变得不安的拐角圆角伪像。

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

另一种方法是在三通道纹理细节中使用三位数的中位数,并在github上提供实现。目的是对以前用于解决此问题的“与”或“黑”进行改进。好的质量稍微慢一点(几乎不明显),但速度慢,但是使用的纹理内存是其三倍。而且,很难获得额外的效果(例如发光)。

最后,存储构成字符的实际贝塞尔曲线,并在片段着色器中对其进行评估已变得很实用,即使在最高放大倍数下,其性能也略逊一筹(但问题不大),并且效果惊人。
WebGL的演示渲染大PDF文件使用这种技术可以实时地在这里


1
它们看起来相当不错(即使使用天真过滤并且没有mipmapping,因为您的纹理很小,并且数据可以很好地插值)。我个人认为,在许多情况下,它们看起来甚至比“真实”的东西还要,因为没有任何暗示性的暗示,这些暗示常常会产生我认为“奇怪”的事物。例如,较小的文本不会突然由于没有明显的原因而变粗,也不会突然出现在像素边界上,而这种效果通常是用“真实”字体看到的。这样做可能有历史原因(1985年的黑白显示器),但是今天,我必须如此理解,这超出了我的理解。
达蒙

2
效果很好,谢谢分享!对于那些想要HLSL frag shader源的人,请参见此处。您可以通过更换适应本作GLSL clip(...)用线if (text.a < 0.5) {discard;}(或text.a < threshold)。HTH。
工程师

1
感谢更新。我希望我能再次投票。
Ben Voigt

2
@NicolBolas:您似乎没有仔细阅读。答案中都解释了这两个问题。开普勒是“最新一代”的例子,没有第二次通过(并解释了原因),我声明我认为虚拟带宽节省技术明显更快或更值得一试。但是,信念没有任何意义-人们必须尝试去了解(我没有,因为我不认为将“正常”数量的文本绘制为瓶颈)。但是,当人们迫切希望获得带宽并拥有“异常”数量的文本时,这可能是值得的。
戴蒙2013年

3
@NicolBolas:对,你说的没错。这确实有点误导。在上一段中,我写了“一个人甚至可能会在GPU上生成它,但是这需要反馈和... isnogud。” -但随后错误地继续执行“从反馈缓冲区生成的数据”。我会改正的。实际上,我将在周末重写完整的内容,这样就不会造成歧义。
2013年

15

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

GLyphy和其他基于SDF的OpenGL渲染器之间的主要区别在于,大多数其他项目都将SDF采样为纹理。这具有采样所具有的所有常见问题。就是 它扭曲了轮廓,质量低劣。GLyphy而是使用提交给GPU的实际矢量来表示SDF。这导致非常高质量的渲染。

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


3
对GLyphy感兴趣的任何人都应该在Linux.conf.au 2014上观看作者的演讲:youtube.com/watch?
Fizz

14

最普遍的技术仍然是纹理四边形。但是在2005年,LORIA开发了一种称为矢量纹理的产品,即将矢量图形渲染为图元上的纹理。如果使用它将TrueType或OpenType字体转换为矢量纹理,则会得到以下信息:

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


2
您知道使用此技术的任何实现吗?
路加福音

2
没有(如生产级),但是Kilgard的论文(请参阅下面的答案以获取链接)有简短的评论,我总结为:尚不实用。该地区有更多的研究。Kilgard引用的最新作品包括research.microsoft.com/en-us/um/people/hoppe/ravg.pdfuwspace.uwaterloo.ca/handle/10012/4262
Fizz

9

令我惊讶的是,马克·基尔加德(Mark Kilgard)的婴儿NV_path_rendering(NVpr)没有被上述任何内容提及。尽管它的目标比字体渲染更通用,但它也可以通过字体和字距调整来渲染文本。它甚至不需要OpenGL 4.1,但目前仅是供应商/ Nvidia的扩展。它基本上将字体转换为路径,使用glPathGlyphsNV该路径取决于freetype2库以获取度量标准,等等。然后,您还可以使用以下命令访问字距调整信息glGetPathSpacingNV并使用NVpr的常规路径渲染机制来显示使用路径“转换后”字体显示的文本。(我将其用引号引起来,因为没有真正的转换,所以曲线按原样使用。)

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

有关字体部分的2011 NVpr API演示文稿演讲从这里开始,在下一部分继续;不幸的是,该演示文稿是如何拆分的。

有关NVpr的更多常规材料:

  • Nvidia NVpr集线器,但登录页面上的某些资料不是最新的
  • Siggraph 2012年论文针对大脑的路径渲染方法,称为“模具,然后覆盖”(StC);本文还简要解释了Direct2D之类的竞争技术是如何工作的。与字体有关的位已降为本文的附件。还有一些视频/演示等附加功能
  • GTC 2014演示文稿的更新状态;简而言之:它现在得到了Google的Skia(英伟达在2013年末和2014年贡献了代码)的支持,而该代码又用于Google Chrome浏览器和[我认为独立于Skia] Beta Adob​​e Illustrator CC 2014中
  • OpenGL扩展注册表中的官方文档
  • USPTO已向Kilgard / Nvidia授予了与NVpr相关的至少四项专利,如果您想自己实现StC,您可能应该知道这些专利:US8698837US8698808US8704830US8730253。请注意,与此类似,美国专利商标局还有另外17篇文档也称为“也发布为”,其中大多数是专利申请,因此完全有可能从这些专利中获得更多专利。

而且,由于在我回答之前,“模具”一词在此页面上没有产生任何点击,因此,尽管有很多,但到目前为止,参与该页面的SO社区的子集似乎并未意识到没有曲面细分,模板缓冲的问题。基于路径/字体渲染的方法。Kilgard 在opengl论坛上有一个类似FAQ的帖子,它可能阐明无细分路径渲染方法与沼泽标准3D图形有何不同,即使它们仍在使用[GP] GPU。(NVpr需要具有CUDA功能的芯片。)

从历史角度看,Kilgard还是经典的“基于简单OpenGL的用于纹理映射文本的API”(SGI,1997年)的作者,不应与2011年首次发布的基于模板的NVpr混淆。


此页面上讨论的大多数(如果不是全部)最近的方法,包括基于模板的方法(如NVpr)或基于SDF的方法(如GLyphy)(我不再在这里讨论,因为其他答案已经涵盖了该方法)有一个局限性:它们是适用于在常规(〜100 DPI)显示器上以任何比例缩放而没有锯齿的大型文本显示,并且即使在小尺寸的高DPI视网膜显示器上,它们也看起来不错。但是,它们不能完全提供Microsoft的Direct2D + DirectWrite所提供的功能,即在主流显示器上提示小的字形。(有关提示的视觉调查,一般请参见此错字式页面。有关更详细的资源,请访问antigrain.com。)

我目前尚不了解任何开放式和产品化的基于OpenGL的功能,它们可以完成Microsoft的提示。(我承认对Apple的OS X GL / Quartz内部组件无知,因为据我所知,Apple尚未发布它们如何基于GL的字体/路径渲染内容。与MacOS 9不同,OS X似乎没有确实存在提示,这使某些人感到烦恼。)无论如何,2013年一篇研究论文通过INRIA的Nicolas P. Rougier编写的OpenGL着色器解决了提示问题。如果您需要从OpenGL进行提示,则可能值得阅读。尽管看起来像freetype这样的库在提示方面已经完成了所有工作,但实际上并非如此,原因如下,我在本文中引用该理由:

FreeType库可以使用RGB模式下的子像素抗锯齿来光栅化字形。但是,这只是问题的一半,因为我们还希望实现子像素定位以精确放置字形。在分数像素坐标处显示纹理四边形并不能解决问题,因为它只会导致在整个像素级别进行纹理插值。相反,我们希望在子像素域中实现精确的偏移(介于0和1之间)。可以在片段着色器中完成此操作。

解决方案并不完全是微不足道的,因此在这里我不再尝试解释。(本文是开放获取的。)


我从Rougier的论文中学到的另一件事(而Kilgard似乎没有考虑过)是(Microsoft + Adob​​e)的字体功能创建了一种而不是两种字距调整方法。旧的基于所谓的kern表,并且由freetype支持。新的称为GPOS,仅在自由软件世界中受较新的字体库(如HarfBuzz或pango)支持。由于NVpr似乎不支持这两个库中的任何一个,因此对于某些新字体,字距调整可能无法与NVpr一起使用。根据该论坛的讨论,其中一些显然是荒野的。

最后,如果您需要进行复杂的文本布局(CTL),则您似乎对OpenGL不太满意,因为为此似乎不存在基于OpenGL的库。(另一方面,DirectWrite可以处理CTL。)像HarfBuzz这样的开放源代码库可以渲染CTL,但是我不知道如何通过以下方法使它们很好地工作(例如,使用基于模具的方法) OpenGL。您可能必须编写粘合代码以提取重新成形的轮廓并将其作为路径输入到基于NVpr或SDF的解决方案中。


4
我没有提到NV_path_rendering,因为它是扩展,是使事情变得更糟的供应商专有。我通常只尝试针对普遍适用的技术给出答案。
datenwolf 2014年

1
好吧,我可以在某种程度上同意这一点。该方法本身(“模板,然后覆盖”)实际上并不难直接在OpenGL中实现,但如果这样简单地完成,它将产生很高的命令开销,因为先前基于模板的尝试最终会结束。据基尔格拉德说,斯基亚(通过Ganesh)在点上尝试了基于模板的解决方案,但放弃了。Nvidia在其下一层使用CUDA功能实现该方法的性能。您可以尝试使用大量EXT / ARB扩展名自己“修饰” StC。但是请注意,Kilgard / Nvidia在NVpr上拥有两项专利申请。
Fizz

3

我认为您最好的选择是研究带有OpenGL后端的开罗图形

开发带有3.3内核的原型时,我唯一的问题是OpenGL后端不赞成使用函数。那是1-2年前,所以情况可能有所改善...

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.