WebGL中更好的文本质量

时间:2014-09-21 05:55:52

标签: javascript html5 opengl-es webgl true-type-fonts

我正在寻找一种在WebGL中绘制更好质量(任意)文本的方法。目前,我在2D画布上使用位图字体渲染,并将它们放入WebGL上下文中。

此处描述了此方法http://delphic.me.uk/webgltext.html

这是我现在知道的在WebGL中绘制任意unicode文本的唯一解决方案。这种方法的问题是这些是位图字体,并且在较小的字体大小上看起来很块。我主要使用的字体大小为18,与桌面质量字体相比,结果相当块状。

我知道threeJS有一个字体库可以生成更好看的文字,但是我不想使用threeJS,因为我有自己的包装器,它可以正常工作,我不需要添加额外的三个开销。

那么如何在WebGL中创建质量更好的文本呢?有没有方法在Javascript中提取文本形状以提高质量?

3 个答案:

答案 0 :(得分:30)

使用Fonts一段时间之后,我可以看到6种在WebGL中进行字体处理的方法,都有优点和缺点:

Font as Geometry

  1. 获取与Google相似的开源字体(Open SansRoboto非常受欢迎)
  2. 使用OpenType或类似的(https://nodebox.github.io/opentype.js/
  3. 读出字体的曲线
  4. 对字符曲线进行三角测量。我最喜欢的是Earcut,因为它非常快https://github.com/mapbox/earcut
  5. 将每个字符的多边形绘制为普通的WebGL三角形。
  6. 优点

    • 非常快,如果你有很多文字并需要全功能字体,这是你最好的选择。通过矩阵操作在GPU上完成字体缩放。

    缺点

    • 呈现字体的质量取决于WebGL浏览器启用的抗锯齿功能。 Safari做8x8 AA看起来不错,但所有其他浏览器只使用4x4,这可能看起来很块。此外,移动浏览器根本不启用AA,因此移动设备上的字体看起来非常模糊。

    帆布

    这也称为" On Demand Dynamic Textures"。将文本字形仅渲染到(屏幕外)画布,并将其作为WebGL纹理显示在屏幕上,如下所述:http://delphic.me.uk/webgltext.html

    优点

    • 体面的品质。

    缺点

    • 速度,取决于您需要在多长时间内呈现的文字数量。特别是如果你只需要渲染静态文本。

    游戏帝国时代III 使用此方法。

    位图字体

    如果您希望为有限的字符集和固定字符大小(游戏)提供最佳质量的最高速度,最好创建自己的位图,其中包含您要使用的字符,并根据需要将它们blit到屏幕上。你可以在互联网上找到很多这些字符位图。

    这既快速又简单,但限制了您可以使用的语言和字符,但您不会在游戏中担心这一点。

    优点:

    • 简单易懂
    • 创建纹理图集的琐碎
    • 可以使用彩色字体

    缺点

    • 放大时看起来非常模糊
    • 必须预渲染所有使用的字形
    • 每个字体大小需要纹理
    • 需要texture bin packing才能获得最佳纹理效果。 Example

    有符号距离字段字体

    Valve的克里斯·格林写了这本书#34;"使用纹理的符号距离字段。您将要阅读2007 SIGGRAPH白皮书"Improved Alpha-Tested Magnification for Vector Textures and Special Effects

    通常字体纹理图集看起来像this。 SDF纹理看起来like。是的,SDF纹理图集在渲染时看起来很模糊"原样"。这是因为8位通道编码为:

    • 0 - > -1.0(外)
    • 255 - > +1.0(内部)

    优点:

    • 单个纹理可用于将字体非常小(6像素)缩放到非常大(200像素+)而不会有任何质量损失,
    • 抗锯齿经常是#34;免费"。

    缺点:

    • 必须预渲染所有使用的字形,
    • 预处理SDF纹理通常是在#34;离线"由于S-L-O-W预处理(约15秒),
    • 没有多少人了解如何生成高质量的抗锯齿。由于人们在纹理空间而不是屏幕空间中进行插值,因此诸如smoothstep()fwidth()之类的黑客会给出质量较差的缩放结果。 WebGL的fwidth()使用错误的常量也没有帮助。
    • 单通道SDF并没有像Valve在他们的论文中暗示的那样保留边缘。他们的解决方案是使用多通道SDF,但没有提供任何细节。请参阅Chlumsky Viktor Master thesis或他的开源msdfgen
    • 需要"细胞填充"如果小尺寸使用SDF字体,则为几个像素的边框。
    • 仅支持单色字体

    所有人都说,如果你有多种字体,那么SDF字体在尺寸(仅需要1)和质量(在小尺寸和大尺寸上看起来都很棒)都可以获得巨大的胜利。

    SDF演示

    GPU上的字体

    人们正在探索将立方曲线存储在GPU上并完全绕过纹理,方法是让智能片段着色器完成所有渲染的繁重工作。

    blog包含截至2017年2月的字体渲染摘要。

    优点

    • 正常和大尺寸的高品质雕文

    缺点

    • 高着色器成本和复杂性
    • 小尺寸的质量问题

    GPU字体演示

    Canvas Overlay

    对于我当前的项目,我使用HTML5 2D画布渲染文本和其他2D基元,并使用WebgGL画布上的透明度覆盖它。我对速度和速度感到惊讶,它在速度和质量方面都非常好。

    只要您的文字是静态2D并且您不需要任何3D转换,这将是我的建议。在我的项目中,这比我之前使用的方法(Font as Geometry)快了约2倍。

答案 1 :(得分:3)

查看three.js的源代码可以找到解决方案。

这里是three.js字体创建的代码 https://github.com/mrdoob/three.js/blob/master/src/extras/FontUtils.js

它在右上角说

 * For Text operations in three.js (See TextGeometry)
 *
 * It uses techniques used in:
 *
 *  typeface.js and canvastext
 *      For converting fonts and rendering with javascript
 *      http://typeface.neocracy.org
 *
 *  Triangulation ported from AS3
 *      Simple Polygon Triangulation
 *      http://actionsnippet.com/?p=1462
 *
 *  A Method to triangulate shapes with holes
 *      http://www.sakri.net/blog/2009/06/12/an-approach-to-triangulating-polygons-with-holes/

Typeface.js provides the font data and there's an online form to convert truetype fonts

其他解决方案:

  1. 将文本渲染到您的位图并获得更高的分辨率,然后将其绘制到分辨率或更小的分辨率。

  2. 使用曲线渲染器。 (http://http.developer.nvidia.com/GPUGems3/gpugems3_ch25.html

答案 2 :(得分:0)

Pixi.js同意上述有关SDF的建议。

https://github.com/PixelsCommander/pixi-sdf-text

他们说(对于浏览器来说,这是一个出色的游戏项目)

  

SDF是在WebGL中绘制文本的最有效方法。它使用特殊的栅格地图集和GLSL着色器在GPU上以非常高效的方式绘制矢量可缩放文本。

this来自MapBox,至少在某个时候也做到了。