最广泛使用的技术仍然是纹理四边形。然而在2005年LORIA开发了一种叫做矢量纹理的东西,即在原语上渲染矢量图形作为纹理。如果有人使用这个转换TrueType或OpenType字体为矢量纹理,你会得到:

http://alice.loria.fr/index.php/publications.html?Paper=VTM@2005 < a href = " http://alice.loria.fr/index.php/publications.html?Paper=VTM@2005 " > < / >

我认为你最好的选择是用OpenGL后端查看开罗的图形

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

不管怎样,我希望将来桌面opengl图形驱动程序能够实现OpenVG。

渲染轮廓,除非你总共只渲染十几个字符,否则仍然是“不可能的”,因为每个字符需要近似曲率的顶点数量。虽然已经有了在像素着色器中评估bezier曲线的方法,但这些方法不容易反锯齿,这在使用距离贴图纹理的四方中是微不足道的,并且在着色器中评估曲线的计算仍然比必要的要昂贵得多。

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

该技巧参见著名的阀纸

该技术在概念上类似于隐式曲面(metaballs等)的工作方式,尽管它不生成多边形。它完全在像素着色器中运行,并将纹理的采样距离作为距离函数。所有超过选定阈值(通常是0.5)的内容都是“在”,其他内容都是“在外”。在最简单的情况下,在10年的无着色功能的硬件上,将alpha测试阈值设置为0.5将会做到这一点(尽管没有特殊效果和抗锯齿) 如果想要给字体增加一点重量(人造粗体),稍微小一点的阈值就可以做到这一点,而不需要修改任何一行代码(只需更改“font_weight”统一)。对于辉光效果,我们简单地认为所有高于一个阈值的东西都是“在”,而高于另一个(较小的)阈值的东西都是“在外,但在辉光中”,以及介于两者之间的lerp。

通过使用8位符号距离值而不是单个位,这种技术将纹理映射在每个维度上的有效分辨率提高了16倍(不是黑白,而是使用了所有可能的阴影,因此我们使用相同的存储空间获得了256倍的信息)。但是,即使你放大远远超过16倍,结果看起来还是可以接受的。长直线最终会变得有点摆动,但不会有典型的“块状”采样工件。

你可以使用一个几何着色器来生成点外的四边形(减少总线带宽),但老实说,增益是相当边际的。GPG8中描述的实例字符渲染也是如此。只有当你有一个很多的文本要绘制时,实例化的开销才会平摊。在我看来,这些好处与增加的复杂性和不可降级性无关。另外,你要么受到常量寄存器数量的限制,要么你必须从纹理缓冲区对象中读取,这对于缓存一致性来说不是最优的(而目的就是优化!) 如果你提前安排上传时间,一个简单的、普通的老顶点缓冲区也一样快(可能更快),并且可以在过去15年里构建的所有硬件上运行。并且,它不受字体中任何特定字符数量的限制,也不受渲染的特定字符数量的限制 如果你确定你的字体中不超过256个字符,纹理数组可能值得考虑以类似于从几何着色器中的点生成四边形的方式剥离总线带宽。当使用数组纹理时,所有四边形的纹理坐标都具有相同的常量st坐标,仅在r坐标上有所不同,这等于要渲染的字符索引 但与其他技术一样,以与上一代硬件不兼容为代价,预期的收益是微不足道的

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

< p > 更新: < br > 正如最近在可编程顶点拉拔中指出的那样(D. Rákos,“OpenGL Insights”,第239页),与使用标准固定函数相比,在最新一代的gpu上,以编程方式从着色器中提取顶点数据没有显着的额外延迟或开销 此外,最新一代的gpu有越来越多的合理大小的通用L2缓存(例如nvidia Kepler上的1536kiB),所以人们可能会认为从缓冲区纹理中提取四角随机偏移时的不连贯访问问题不太成问题

这使得从缓冲区纹理中提取常量数据(如四元大小)的想法更有吸引力。因此,一个假设的实现可以通过以下方法将PCIe和内存传输以及GPU内存减少到最小:

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

像这样,理想情况下可以将所需的顶点带宽减少75%(平摊),尽管它只能渲染一条线。如果想要在一个draw调用中渲染几行,就需要将基线添加到缓冲纹理中,而不是使用统一的(使带宽增益更小)。

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

上面已经提到了“OpenGL的见解”,有必要指出Stefan Gustavson的基于距离域的二维形状绘制章节,其中详细解释了距离场渲染。

2016年更新:

同时,还有一些其他的技术,旨在消除在极端放大时变得令人不安的圆角人工制品。

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

另一种方法在三通道纹理细节和实现可以在github上找到中使用三的中间值。这旨在对以前用于解决该问题的and-or黑客进行改进。质量好,稍微慢一点,几乎不明显,但是使用了三倍的纹理内存。另外,额外的效果(例如发光)也很难得到正确的效果。

最后,存储构成字符的实际bezier曲线,并在片段着色器已经变得实际中对它们进行评估,性能略差(但没有到成为问题的程度),即使在最高放大倍率下也会产生惊人的结果 WebGL演示渲染一个大的PDF与此技术实时可用在这里

http://code.google.com/p/glyphy/ < a href = " http://code.google.com/p/glyphy/ " > < / >

GLyphy和其他基于SDF的OpenGL渲染器之间的主要区别是,大多数其他项目都将SDF采样到纹理中。这包含了所有抽样的常见问题。Ie。它扭曲轮廓和低质量。这将导致非常高质量的渲染。

缺点是该代码是针对带有OpenGL ES的iOS。我可能会做一个Windows/Linux opengl4。X端口(希望作者会添加一些真正的文档)。

我很惊讶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演讲表示更新状态;简而言之:谷歌的Skia现在支持它(Nvidia在2013年底和2014年贡献了代码),这反过来又被用于谷歌Chrome和Adobe Illustrator CC 2014的测试版中[独立于Skia,我想]
  • OpenGL扩展注册表中的官方文档
  • USPTO已经向Kilgard/Nvidia授予了至少四项与NVpr相关的专利,如果你想自己实现StC,你可能应该知道:US8698837US8698808US8704830US8730253。请注意,还有大约17份USPTO文件与此相关,其中大部分是专利申请,所以完全有可能从这些文件中获得更多专利。

由于“模板”这个词在我回答之前并没有在这个页面上产生任何点击,到目前为止,参与这个页面的SO社区的子集,尽管数量相当多,但总体上不知道无镶嵌,基于模板缓冲区的路径/字体渲染方法。Kilgard有一个类似faq的帖子在opengl论坛上,它可以说明无镶嵌路径渲染方法与沼泽标准3D图形的区别,即使他们仍然使用[GP]GPU。(NVpr需要一个cuda芯片。)

从历史的角度来看,Kilgard也是经典“一个简单的基于opengl的纹理映射文本API”,SGI, 1997的作者,它不应该与2011年推出的基于模板的NVpr混淆。


大多数(如果不是所有)最近讨论的方法,包括基于模板的方法,如NVpr或基于sdf的方法,如GLyphy(我在这里不再讨论,因为其他答案已经涵盖了它),但有一个局限性:它们适用于传统(~100 DPI)显示器上的大文本显示,在任何缩放级别上都没有锯齿,即使是小尺寸,在高DPI,视网膜状显示器上看起来也很好。然而,它们并不能完全提供微软的Direct2D+DirectWrite所提供的功能,即在主流显示器上显示小符号。(对于一般提示的可视化概览,请参见这个排版页面。更深入的参考资料是在antigrain.com上。)

我不知道有什么开放的&产品化的基于opengl的东西,可以做微软目前可以用暗示做的事情。(我承认我对苹果OS X GL/Quartz内部结构一无所知,因为据我所知,苹果还没有发布他们是如何进行基于GL的字体/路径渲染的。似乎OS X,不像MacOS 9,根本不做提示,惹恼一些人。)不管怎样,INRIA的Nicolas P. Rougier写了2013年的一篇研究论文,讨论了通过OpenGL着色器进行暗示;如果你需要在OpenGL中做提示,它可能值得一读。当涉及到提示时,看起来像freetype这样的库已经完成了所有的工作,但实际上并非如此,原因如下,我引用了论文中的内容:

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

这个解不是很简单,所以我就不解释了。(这篇论文是开放获取的。)


我从Rougier的论文中学到的另一件事(Kilgard似乎没有考虑到这一点)是字体的权威(Microsoft+Adobe)已经创建了不止一种而是两种字距规范方法。旧的表基于所谓的克恩表,freetype支持它。新的字体库叫做GPOS,它只被自由软件世界中的HarfBuzz或pango等较新的字体库所支持。由于NVpr似乎不支持这两种库,对于一些新字体,字面值可能无法在NVpr中开箱即用;根据本次论坛讨论,有一些显然在野外。

最后,如果你需要做复杂文本布局(CTL),你目前似乎没有OpenGL的运气,因为没有基于OpenGL的库似乎存在。(另一方面,DirectWrite可以处理CTL。)有像HarfBuzz这样的开源库可以渲染CTL,但我不知道如何通过OpenGL让它们工作得很好(就像使用基于模板的方法一样)。您可能必须编写胶水代码来提取重新形状的轮廓,并将它们作为路径提供给基于NVpr或sdf的解决方案。