文本(渲染)的艺术¶
标题:The art of text (rendering)
日期:2025/12/27
作者:Nicolas Rougier
链接:https://media.ccc.de/v/39c3-the-art-of-text-rendering
注意:此为 AI 翻译生成 的中文转录稿,详细说明请参阅仓库中的 README 文件。
谢谢大家,早上好。是的,今天的讲座题目是关于文本渲染的艺术,我应该特别说明是实时渲染(real-time rendering),因为当然,如果你想做文本渲染,你大可以使用 LaTeX。但是当你尝试做实时渲染时,情况就有点不同了。
正如刚才介绍的,我主要是一名神经科学研究员,但我需要开发一些软件来对数据进行实时可视化。当时我想,“好吧,没问题,我只需要把字母一个接一个地放好,问题就解决了。” 然后我接触到了排版(typography),我才发现这比简单地把字形(glyph)并在起要困难得多。实际上,如果你想要正确的文本渲染,你需要执行很多规则。这是一件非常痛苦的事情,但你是可以做到的。如果你不知道这些规则,屏幕上就会显示出一堆垃圾。
这就引出了一些例子。这个例子来自一个叫“Not Arabic(不是阿拉伯语)”的博客。如果你懂阿拉伯语,你会发现这根本不是阿拉伯语,因为它没有对字形进行塑形(shape)。这意味着这对阅读阿拉伯语的人来说只是一堆乱码。当然,在电子游戏中,他们只是把一些阿拉伯语字形放上去,然后说,“行了,这样就行了。” 但其实不行,这是一个问题。
另一个例子更近一些,现在仍然存在。这是关于 Unicode(万国码) 的。我会解释什么是 Unicode。但在 Unicode 之前,我们有所谓的字符集(character set)。当你编码文本时,你需要知道使用的是什么字符集。如果你不这样做,就会有问题,因为你试图解码——比如用 ASCII 码去解,结果发现其实是中文,然后当然屏幕上就会出现乱码。这种情况现在仍然存在,因为如果你有旧的文本,你试图将其作为 Unicode 读取,但它并不是 Unicode,你就会得到这种结果。当然,你还可以增加一些乐子。
还有一个例子,抱歉,是关于 字距调整(kerning) 的,这非常重要。好的,你们看到问题所在了。字距调整我稍后也会解释,它是指当你希望两个字母靠得更近时,因为从美学角度来看这样更好。当然,你必须小心,因为对于某些单词,如果字距调整得很糟糕——这被称为“keming”——那么你读出来的词可能会变味。例如,这里有个词是“right click”(右键点击),如果有糟糕的字距,你可能会把它读成“right dick”。例如,苹果公司非常清楚这个问题,当他们的网站上有“click”这个词时,他们会明确地在 C 和 L 之间加一个空格,以确保它读起来是 click。而对于其他人,比如 Rockstar Games,他们只是完全删除了空格,然后你就看到了“click lovers”(点击爱好者,看起来像 dick lovers),这就跨过了令人惊讶的门槛。这只是想说明,如果你不执行所有规则,你就会得到这种结果。
对于某些软件工程师来说,他们会觉得:“行了,我能读懂这行字,有什么关系呢?有什么问题吗?” 嗯,好的,正如你所见,问题很多。
当我们深入研究排版时,还有很多其他术语。我不会解释所有内容,因为这是一个巨大的领域,但你至少要考虑几件事。
第一件事是文本如何编码。现在,Unicode 已经存在 30 多年了。Unicode 是一场革命,因为它简化了一切。你可以读取文本,而不需要知道字符集是什么。在此之前,你必须知道它是 ISO Latin 1、ASCII 还是中文等等。你有着各种各样的字符集。有了 Unicode,你可以编码地球上的每一种语言。你有不同的方式来实现它,你可以使用 UTF-32、16 或 8。Unicode 的美妙之处在于它与 ASCII 兼容。所以如果你有一个用 ASCII 编码的文本,你可以将其作为 Unicode 解码,它也能正常工作,这很好,避免了很多问题。每年都有新的字形被添加到 Unicode 标准中,所以它在不断增长。现在,我们要覆盖 170 种语言的 150,000 多个字符,这是相当巨大的。但这仅仅是编码。
读取文本并解码后,你必须选择一种字体(typeface),也被称为字体家族(Font Families)。给你举几个非常有名的字体例子,它们实际上很古老。当然,它们主要是为欧洲语言设计的。所以,你显然不能用这种字体渲染所有内容。对于不属于你字体中的其他代码(字符),你需要添加其他字体。目前有一些努力试图拥有一种可以渲染所有内容的字体。一个例子是 Noto 字体,其想法是我想用同一种字体渲染任何语言,这是一项巨大的工程。这个字体叫 Noto 是取自 “No Tofu”(没有豆腐块)。所谓的“豆腐块”,就是当字形在你的字体中不可用时,你会得到那个奇怪的方块字符,表示“好吧,我无法渲染这个字符,因为它不是字体的一部分”。
接下来是基础排版。这是一些非常简单的规则。我已经谈到了字距调整(Kerning)。字距调整实际上纯粹是美学。例如,当你把 A 和 V 放在一起时,你想让 V 离 A 近一点,因为这样更好看。这在罗曼语族中很常见。这意味着在字体文件中,有明确的指令说:“哦,当你有 A 后面跟着 V 时,就这样做。”
然后是连字(Ligature)。连字也纯粹是美学。这意味着,例如,当你有一个双 F(ff)时,你有一个特定的字形来表示双 F。所以它会用这个特定的字形替换两个 F。这对 f 和 i 以及其他一些组合也是如此。
接着是变音符号(Diacritic mark)。这些不仅仅是美学,它们真的很重要。它是指你如何使用一些标记来转换字形。这在某些语言中非常重要。也许在某些语言中不那么重要,但大多数时候,它真的很重要。
然后是字体微调(Hinting)。我也会说几句。我会解释微调,这是指当你有非常小的字体时,你希望你的字体适应像素网格,因为这样对眼睛来说更舒服。
还有所有的字体度量(Face metrics)。这里只有几个例子,比如上伸部(ascender)、大写高度(cap height)、中线(median)、基线(baseline)。这是关于如何在一行上对齐文本。你必须考虑到所有这些。这就是基础部分。
然后你有更高级的东西。其中之一叫做文本塑形(Text shaping)。这就是刚才阿拉伯语的例子。黑色的那个是没有塑形时的样子,也就是垃圾乱码。如果你想做对,你必须得到右边那个样子的结果。
还有替代样式(Alternate style)。这也是编码在字体中的。
还有复杂文本布局(Complex text layout)。这同样涉及到你获得的编码内容和你需要渲染的内容(红色部分)。这也相当复杂。当然,你可以混合语言,有些是从左到右,另一些是从右到左。所以在渲染文本时,你也必须考虑到这一点。
总而言之,有很多规则。当然,你还有其他形式的复杂布局。今天早上我只谈论文本,但当然,你也可以渲染化学式、数学公式或音乐符号。同样,这些也有不同的规则。
现在你的文本解码了,你有字体了,好吧,我们可以用字体做什么?如果你研究一下字体格式,主要有两种类型。一种是 PostScript,现在用得不多了。另一种是 TrueType。它们主要用一组 贝塞尔曲线(Bezier curves) 来描述每个字母。简单提醒一下,什么是贝塞尔曲线?简单来说,你有三个点来控制曲线的斜率。作为设计师,你的工作就是用所有这些曲线来描述你的字形,这对软件开发人员来说简直是一场噩梦,因为它们没有好的数学属性。例如,当你试图计算到一个贝塞尔曲线的距离时,如果是二次曲线还不是特别容易,如果是三次曲线那就真的非常非常难。但无论如何,这是编码字形的格式。
这是一个贝塞尔曲线的例子。这是你在屏幕上看到的,而背后是所有不同的曲线。所以当你渲染一个字形时,你有这些曲线,你的工作就是尝试正确地渲染它。
在字体表中,你有所有关于字距调整、塑形、字形替换、替代样式等的不同指令。这又是一个相当复杂的格式。主要有两个库。一个是 FreeType。FreeType 无处不在。例如,如果你看你的手机,你可能会在系统里找到 FreeType 的许可证。HarfBuzz 是另一个必需的库,它是一个塑形引擎。例如,当你有一堆阿拉伯语字形时,它会告诉你如何渲染它。
如果我们看看渲染管线,它是这样的。很长一段时间以来,我们要么有所谓的“拉丁语捷径”。就像,“哦,你有文本缓冲区,我有字体,渲染它就行了。” 当然,这在 ASCII 时代行得通。对于其他语言,这不再适用了。所以你需要做的第一步是项目化(Itemization)。识别哪部分是英文,哪部分是阿拉伯语。你必须根据从左到右或从右到左进行重排序(Reorder)。然后是塑形(Shaping)。如何将字形组装在一起?可能还有对齐(Justification)。关于如何进行正确的对齐也有大量的文献。最后,你才能在屏幕上渲染你的字形。好的?所以这是一大堆操作。而且你想实时完成这些。这也是困难之一。
现在,我们一切准备就绪,要在屏幕上渲染一个字形。问题是,如果不这样做会怎样?事情已经改变了,因为现在我们有 GPU(图形处理单元)。它们致力于图形渲染。在 90 年代末,很早的时候,有一个非常简单的想法:“哦,我把字形渲染到一个纹理上,然后在屏幕上显示这个纹理。” 所以你必须将字形 光栅化(rasterize) 到纹理中,然后你可以用它来显示。
当然,当你做光栅化时,你有很多不同的选择。因为同样,你有描述字形的连续贝塞尔曲线,但你必须在像素网格上显示它。如果你的 DPI(每英寸点数)不够高,你就必须在屏幕上伪造抗锯齿(anti-aliasing),只是为了有一个更好的形状。这里有几个关于如何进行光栅化的例子。例如,取决于你的系统,如果你在 Windows 或 Apple 上,你可以识别出他们在系统上如何实现抗锯齿。这是非常有特征性的。这就背后有很多研究,也有很多不同的模式。现在的想法是,要么你尊重字形的形状,要么你试图强制适应像素网格。你有一个选择。
除此之外,你还可以玩很多花样。当然,你有Gamma 校正。这是为了适应人类感知而调整亮度。你可以玩转能量分布。例如,当你有黑色背景上的白色文本时,你可以根据亮度改变渲染方式。反之亦然。你可以强制进行微调(Hinting)。再次强调,微调就是当你试图让字形适应像素网格时。很多人都这样做。你可以在长文本行中看到差异。上面那行是平滑的;而对于下面那行,字符在文本长度方向上会有跳跃,仅仅因为它适应了这个像素网格,然后又适应另一个像素网格。
从这个简单的纹理映射的想法开始,这确实是一个很好的主意,因为就 GPU 而言,你只需要用你的纹理渲染两个三角形。你可以旋转它,在一定程度上缩放它。然后你可以把很多字形打包到一个纹理中。这是一个例子。你可以在单个纹理中放入相当多的字形。然后你可以在游戏甚至浏览器中使用它。当然,质量嘛,可以说是“还行”,因为如果你对纹理进行大倍率放大,你会开始看到很多伪影(artifacts)。所以这对于游戏来说是可以的。也许对于文档来说就不太好了。如果你用这种技术在屏幕上渲染 PDF,可能不是最好的。
一种改进渲染的方法是强制执行所谓的垂直微调(Vertical Hinting)。解释一下微调:左边的图,你能看到吗?好的,不,你们看不到我的鼠标曲线。当没有微调时,你的形状是贝塞尔曲线,后面是所有的像素,根据它们是在形状内部还是外部来决定开启或关闭。在边界上,你会放一些抗锯齿。对于原生微调(Native Hinting),也就是字体设计师,针对这个特定的尺寸,会说:“哦,你需要修改路径以适应网格。” 这样会好一点。但你也有自动微调(Auto-Hinting)。你试图自动计算一切,但这不如原生微调那么好。最后一种是垂直微调。你只在垂直方向强制执行微调,而在水平方向保持自由。当你这样做时,你可以有非常精确的渲染。因为你可以把你的文本放在十分之一像素的位置。所以你不必把文本对齐到像素网格上,你可以把它放在任何地方。当然,这只适用于水平文本。但它提供了相当好的质量。
然后,你会遇到另一个问题,叫做子像素动物园(Subpixel Zoo)。有一个很棒的网站展示了所有不同的显示器。取决于你是在电脑上、手机上,还是一些奇怪的手机或奇怪的屏幕上,这才是真正的“像素”。我刚才解释抗锯齿时,大部分时间我们使用的是 LCD。这是第二种情况。你利用这样一个事实:真正的像素是由蓝、绿、红的 LED 组成的。如果你改变顺序,你就必须改变你的抗锯齿算法。如果你有其他奇怪的屏幕,那就是另一个问题了。我不知道有没有针对其他类型屏幕的研究。但是,你必须调整你的抗锯齿以适应人类感知。当然,如果你有非常高的 DPI,那就没问题了,因为在某种程度上,你不再需要抗锯齿了。
第二种渲染技术是使用所谓的有向距离场(Signed Distance Fields, SDF)。这个也非常棒。现在的思路是,我们不再试图在纹理内部进行光栅化,而是计算到形状边缘的距离。例如,这里有一个 R。我们可以做的是,对于外部的像素,我们说,“哦,距离是,不知道,10 个像素。” 当你在内部时,它将是一个负距离。利用这种信息,我们可以在 GPU 内部决定像素是在外部、内部还是在边界上。当它们在边界上时,我们可以应用抗锯齿。
这里有一个渲染图。这是相同的编码。我们还可以稍微扩大形状或使其模糊。我们可以做各种各样的事情。这是大约 20 年前引入的。这是一个例子,当你使用 Alpha 混合时,意味着你直接使用纹理,你会看到有很多伪影。而在右边,同样的纹理,但实际上里面存的不是字形本身,而是编码进纹理的符号距离。仅仅因为这种转换,我们可以正确地渲染字形。
Chlumsky 在 10 年前改进了这项技术,因为在纹理中,你有四个通道:RGBA。实际上你可以编码更多的信息。这就是他所做的,称为多通道 SDF(MSDF)。这样你就有了更高的精度。你看看区别。这里是多通道的,你可以正确渲染字母 A。这是单通道同样大小的情况,用 SDF 渲染时,质量不那么好。所以 MSDF 是一个相当不错的改进,计算起来真的很快。这是一个在游戏中投影的例子,在这种情况下,你会得到清晰的纹理渲染。
另一种方法,我谈到了贝塞尔曲线,贝塞尔曲线很难处理,因为它们没有好的属性。你可以做的是尝试用 圆弧(Arc circles) 来近似贝塞尔曲线。如果你能做到这一点,那么计算到一个圆的距离真的很简单。比起贝塞尔曲线简单多了。所以难点在于,给定一组贝塞尔曲线,如何将它们转换为圆弧。如果你能做到这一点,问题就解决了。这就是 Behdad Esfahbod 用 Glyphy 所做的。然后你可以把所有东西编码进去。我不会详述细节,但这就是背后的样子。这是 GPU 内部着色器(shader)处理的内容。你需要额外的信息来渲染一个字形。效果相当不错,但问题是你必须计算这种近似。
现在的第三种技术,可能是今天使用最多的,因为 GPU 现在非常强大。而且,我们有所谓的计算着色器(Compute Shaders)。在计算着色器之前,我们只能用 GPU 做一些图形操作。现在,我们有一个完整的管线可以计算东西。这种想法是,我们不预先渲染任何东西。我们将信息发送到 GPU,它会计算所需的内容。
最著名的算法之一来自 Loop 和 Blinn。这是关于如何渲染与分辨率无关的贝塞尔曲线的。这就是当你有一个像这样的字母 E 时的样子。首先,对于字形的内部,它只是一堆三角形。对于曲线部分,这是他们添加特定着色器的地方,顺便说一下,这曾经是有专利的。不过现在专利过期了,但在当时是有专利的。你可以这样做。这在某种程度上是一场革命,因为它非常快。对于着色器来说,计算这个非常快。所以现在只需要描述一组三角形和一组贝塞尔曲线,然后你就可以渲染它了。
人们改进了这些技术。你有各种预处理。你可以渲染,再说一次,任何字形。其中一个……好的,这是一个关于着色器上实际发生情况的例子。当然,这实际上……甚至不需要几毫秒。使用这些技术的库,据我所知主要有两个。一个叫做 Slug Library。在这种情况下,它将所有字形编码为一种发送到 GPU 的特定格式。然后,它可以毫无问题地进行实时渲染。当然,取决于你的字体的复杂性,它会花费更多时间。例如,Wildwood 字体,到处都有很多装饰,当然这意味着更多的贝塞尔曲线,你必须处理它们。这与以前的技术不同。因为以前的技术,你预先渲染好东西,然后可以随时使用。但尽管如此,它仍然非常快。遗憾的是,它不是开源的。
另一个很有名的是 Pathfinder。它是用 Rust 编写的。而且它很快。这或多或少是同一套技术。思路是你想把所有信息发送到 GPU,GPU 可以为你做一切。当然,你仍然必须考虑到塑形等问题。这类技术被用于,例如,当你在浏览器中时。你需要一个快速的文本引擎来渲染你的文本。
我就讲到这里。正如我解释的那样,有很多可用的技术。选择实际上取决于你想达到什么目的。例如,如果你在做一个游戏,也许把文本作为普通字体或者 SDF 就可以了。没问题。当然,如果你在在线运行一个包含大量排版或数学公式等的文档,你希望有一个非常精细的渲染。Pathfinder 是一个选择(它有第三个版本)。Slug Library 和 MSDF 也许是主要的参与者。
MSDF,即多通道 SDF,因为它非常容易实现。有一个开源库。你计算到字形的距离,这是由库提供的。它会编码一切,然后你只需要一个着色器,问题就解决了。
对于其他的,像 Pathfinder 和 Slug,稍微复杂一点,因为你必须考虑很多事情。因为即使是贝塞尔曲线,你也可能有一些非常具体的情况。
微调(Hinting)。也就是将你的文本适应像素网格,这仍然是需要的,因为周围仍然有一些 DPI 不那么高的屏幕,所以你想适应它以获得更好的渲染。
还有抗锯齿,在我们获得超过 600 DPI 的屏幕之前,这仍然是需要的。所以我们需要测试它。
还有复杂文本布局,也就是塑形。这真的很难。所以你真的不能自己做。如果你想正确渲染地球上的任何语言,你必须使用 HarfBuzz 库。
此外,还有一个问题是周围有很多专利。所以取决于你在地球上的哪个地方,你要么不在乎软件专利,要么你在乎,那就不得不等几年。
感谢大家的关注。我准备了我自己的问题。如果你们有其他问题的话。我也许根本没谈的一件事是可变字体(Variable fonts),因为明天下午 Bern 会有一个相关的讲座。可变字体简直是一场噩梦。噩梦是因为现在不再是静态字形,你必须在每一帧进行调整。就像大会这里有一个带有许多漂亮效果的 Logo。当你对其进行动画处理时,这意味着你每次都要重新计算所有内容。
谢谢。
主持人: 非常感谢你这深入浅出的关于文本渲染的精彩演讲。我也没想到能学到这么多东西。我们现在有时间提问。你们可以看到这里有麦克风。如果你想问演讲者问题,请前往标记好的麦克风处。我们会叫你。与此同时,我们有来自信号天使(Signal Angel,负责网络观众提问的志愿者)的问题吗?
信号天使: 是的,我们有。互联网想知道:与微调(hinting)和塑形(shaping)相比,渲染(rendering)的计算强度有多大?也就是说,渲染是目前最大的瓶颈吗?
演讲者: 好问题。我认为现在的渲染相当快。尤其是因为 GPU 越来越强大。所以塑形可能是最耗时的部分。但实际上,如果你不对文本进行太多的转换,塑形只需要做一次。例如,当你渲染 PDF 时,你计算塑形。然后你可以缩放、平移等。所以它们不在同一个阶段。现在,如果你在文字处理器中输入内容,你就必须重新计算塑形,至少是局部重新计算以考虑这一点。所以,是的,我认为由于移动设备或计算机内部 GPU 的强大能力,渲染现在真的非常非常快。但这实际上需要核实一下。谢谢。
主持人: 请二号麦克风。
提问者: 文本塑形(text shaping)在多大程度上是特定于字体的?像字体拥有有向距离场(SDF)这样的东西,会对塑形本身有帮助吗?
演讲者: 抱歉,我不确定……抱歉,我不确定我听清了。
提问者: 文本塑形在多大程度上是特定于字体的?你提到可以提前进行塑形。
演讲者: 塑形是特定于语言的。所以你必须,例如对于阿拉伯语。当你解码文本时,你有所有的字形。当你使用 FreeType 时,读取,甚至不是 FreeType,你读取所有的字形。然后你必须调用塑形功能说:“好的,你有这个字符和这个字符相邻,你必须用这个字形替换它们。” 然后你有另一个字符,它说:“哦,不,忘了前面的,现在你必须把所有东西连在一起。” 这对于阿拉伯语是这样,对于印地语、梵语也是如此。所以每种语言可能有不同的规则。然后当然,你的字体(typeface)需要包含这些字形。如果你没有这些字形,那么……例如在拉丁语中,至少在法语里,我们有 FF,这是一个连字。所以你可以用这个特定的字形替换双 F。但如果你的字体不提供这个双 F,那么你要么回退到分开的两个 F,要么你放一个“豆腐块”(方框)……
主持人: 谢谢。一号麦克风。
提问者: 是的,我想问一下,在你给出的所有微调(hinting)示例中,看起来唯一改变的是字形轮廓的位置。我想问,通常看起来字形的形状也会改变,被挤压之类的。微调也会发生这种情况吗?
演讲者: 是的,所以例如,当你使用距离场或使用 CPU 渲染字形时,你可以改变……例如,如果你想给字形添加轮廓(outline),你可以在着色器中这样做。如果你想有斜体,你可以……所以你可以稍微玩一下字形的形状。例如,你可以让它变模糊。如果你想有,例如,字形的投影(drop shadow),首先你计算一个非常模糊的抗锯齿字形,然后把实际的字形放在上面。所以一旦你在着色器中使用 GPU 渲染或 SDF 渲染做事情,你就可以在这个形状上玩很多花样。但如果你想真正地把你的,比如说,A 变成 B,那就有点不同了。我们明天会看到,例如对于可变字体,对于以前典型的可变字体,你会有一个粗体字体、一个细体字体、一个常规字体,现在你有一种滑块,可以从细体变为粗体,然后你可以改变字形的实际形状。
提问者: 我指的是别的意思,不过我把时间留给其他人吧。
主持人: 也许我们要去二号麦克风,那位已经等了很久了。
提问者: 谢谢。我主要想知道你介绍的那三种文本渲染方式。当你开始在渲染管线中引入 不透明度(opacity) 时,你认为哪一种最友好?这说得通吗?
演讲者: 是的,对于不透明度,如果你使用纹理和有向距离场(SDF),你可以处理它,因为在 GPU 内部,你有不同的 Alpha 合成模型,所以你可以利用它来进行正确的渲染。当你使用 CPU 时,我认为这也是可行的,因为你在字形内部没有自相交,所以应该能正常工作。难点在于当你有带有不透明度的抗锯齿时,如果不是完全不透明,你就必须调整你的抗锯齿以适应不透明度,这在某些情况下可能有点棘手。但大多数时候,不透明度处理得还不错。
主持人: 谢谢。让我们去三号麦克风。
提问者: 嗨。我很好奇你是否有关于在存在连字(ligatures)时如何处理 光标位置(cursor positions) 的经验或看法。比如在编辑文本时。因为突然之间,我想插入中间的两个字母变成了一个字素。
演讲者: 是的,好问题。如果你没有这方面的经验也没关系。
演讲者: 我实现过连字,我想我只是替换了字形。因为在字体中,当你放置一个字形时,你有所谓的“步进(advance)”,它说明你需要前进多少。我认为这是相当自动的,因为对于连字,例如对于双 F,你会得到与这个特定字形相关的步进信息。所以应该没问题。但我没有检查的是,例如,如果你在连字之后有字距调整,我想我在我的渲染中没有考虑到这种情况。但我确信 HarfBuzz 会处理这个,但是是的。
提问者: 是的,我一直在使用 HarfBuzz,但它也是一个庞然大物,总是有点难。谢谢。
主持人: 是的,好观点。四号麦克风。
提问者: 嗨。我想知道,既然你说贝塞尔曲线真的很难计算,你可以用圆弧来近似它们。你知道有什么文件格式实际上是提前存储预计算好的圆弧以节省计算量的吗?这会有优势吗?我知道贝塞尔曲线是标准,但我有点好奇,也许因为存储空间很便宜,所以甚至即使圆弧数据更大,也许构建一种文件格式也是有意义的……
演讲者: 是的。对于字体,我不知道有任何格式,但我怀疑对于其他处理几何形状的软件,可能有特定的格式。对我们来说,最简单的方法是说服那些排版机,“好吧,忘掉贝塞尔曲线,用圆做所有事情吧。” 是的。但我肯定他们不会那样做。但是,是的,我不知道有任何格式,但这可能会更容易。是的。你拿一个字体文件,重新记录所有内容,那样会更容易。
提问者: 好的。那这项工作总是可以提前完成吗?
演讲者: 是的。所以你知道,对于 Glyphy,它是即时(just-in-time)完成的。但计算近似值需要很长时间。是的。一旦你有了近似值,那就没问题了。
提问者: 好的。但这意味如果你有一个新字体,你需要预处理字体来做所有的近似。然后就可以了,但是……
演讲者: 好的。是的。所以你可以在编译时做,然后把它烘焙进你的游戏之类的?
提问者: 是的。是的。如果能的话……这也是 SDF 的做法。你只需预先计算所有内容,并将字体存储为有向距离场。你也可以对圆弧做同样的事情并读取它。
演讲者: 是的。好的。谢谢。很高兴见到你。