使用 Earcut 对来自 OpenType.js 的路径数据进行三角测量
Triangulate path data from OpenType.js using Earcut
我有一个用例,我需要在 canvas 元素上呈现 显着 数量(~50,000 个字形)清晰、可缩放的文本字符串。到目前为止,我尝试过的 最佳 解决方案涉及对在 canvas 元素上绘制的文本进行三角剖分(文本是使用 fillText 方法绘制的),上传矩阵制服和代表该元素的三角形 Float32Array字符串通过 WebGL 传输到 GPU。使用这种方法,我能够以大约 30fps 的速度渲染 100,000 个字形。字形在非常高的缩放级别变得块状,但这对我的用例来说很好。
但是,此方法每个字符串的开销约为 250 毫秒,因为我首先将字符串绘制到内存中的 canvas 元素,读取像素数据,将位图图像转换为矢量,然后对矢量数据。在网上搜索解决方案时,我遇到了两个有趣的开源项目:
- OpenType.js: https://opentype.js.org/
- 耳切:https://github.com/mapbox/earcut
所以现在我想重新编写我最初的概念证明以使用 OpenType 和 Earcut。 OpenType 用于将曲线数据输入 Earcut,Earcut 用于对该数据进行三角测量并返回表示每个三角形的点的数组。
我的问题是,我不知道如何获取 OpenType 提供的数据并将其转换为 Earcut 接受的格式。有人可以为此提供帮助吗?
更多信息:
这个 Whosebug 问题提供了一些很好的信息,但缺少一些实现细节:Better Quality Text in WebGL。我想我想要完成的是第一个答案中描述的 "Font as Geometry" 方法。
您可以使用 Font.getPath
创建路径。路径由移动到、直线到、曲线到、四边形到和关闭指令组成,可通过 path.commands
访问。当然,您需要先将贝塞尔曲线指令转换成小段。
一旦你有了一组闭合路径,你需要确定哪些是洞。内部轮廓的方向与外部轮廓相反,您可以将它们分配给包含它们的最小外部轮廓。一旦你有了一组 你应该能够将它提供给 earcut 库。
这是一个假设没有交叉点的简单实现。对我来说,它适用于大多数字体,除了极少数具有相交路径的 "fancy" 字体。
这是一个工作示例:https://jsbin.com/gecakub/edit?html,js,output
除了为每个字符串创建网格,您还可以为单个字符创建它们,然后使用库中的字距微调数据自行定位它们。
编辑:此解决方案仅适用于 TTF 字体,但可以通过忽略路径方向并使用更好的 "path A is inside path B" 检查,除非字体有交叉路径。
我有一个用例,我需要在 canvas 元素上呈现 显着 数量(~50,000 个字形)清晰、可缩放的文本字符串。到目前为止,我尝试过的 最佳 解决方案涉及对在 canvas 元素上绘制的文本进行三角剖分(文本是使用 fillText 方法绘制的),上传矩阵制服和代表该元素的三角形 Float32Array字符串通过 WebGL 传输到 GPU。使用这种方法,我能够以大约 30fps 的速度渲染 100,000 个字形。字形在非常高的缩放级别变得块状,但这对我的用例来说很好。
但是,此方法每个字符串的开销约为 250 毫秒,因为我首先将字符串绘制到内存中的 canvas 元素,读取像素数据,将位图图像转换为矢量,然后对矢量数据。在网上搜索解决方案时,我遇到了两个有趣的开源项目:
- OpenType.js: https://opentype.js.org/
- 耳切:https://github.com/mapbox/earcut
所以现在我想重新编写我最初的概念证明以使用 OpenType 和 Earcut。 OpenType 用于将曲线数据输入 Earcut,Earcut 用于对该数据进行三角测量并返回表示每个三角形的点的数组。
我的问题是,我不知道如何获取 OpenType 提供的数据并将其转换为 Earcut 接受的格式。有人可以为此提供帮助吗?
更多信息:
这个 Whosebug 问题提供了一些很好的信息,但缺少一些实现细节:Better Quality Text in WebGL。我想我想要完成的是第一个答案中描述的 "Font as Geometry" 方法。
您可以使用 Font.getPath
创建路径。路径由移动到、直线到、曲线到、四边形到和关闭指令组成,可通过 path.commands
访问。当然,您需要先将贝塞尔曲线指令转换成小段。
一旦你有了一组闭合路径,你需要确定哪些是洞。内部轮廓的方向与外部轮廓相反,您可以将它们分配给包含它们的最小外部轮廓。一旦你有了一组
这是一个假设没有交叉点的简单实现。对我来说,它适用于大多数字体,除了极少数具有相交路径的 "fancy" 字体。
这是一个工作示例:https://jsbin.com/gecakub/edit?html,js,output
除了为每个字符串创建网格,您还可以为单个字符创建它们,然后使用库中的字距微调数据自行定位它们。
编辑:此解决方案仅适用于 TTF 字体,但可以通过忽略路径方向并使用更好的 "path A is inside path B" 检查,除非字体有交叉路径。