3D 文本
前言
项目中不仅会要在 HUD 中使用文本,有时也会需要把文本作为 3D 场景的一部分。Godot 为此提供了两种方法。Label3D 节点以及 MeshInstance3D 节点的 TextMesh 资源 。
此外,Godot 还可以使根据 3D 顶点在相机上的位置来定位控制节点成为可能。在 Label3D 和 TextMesh 不够灵活的情况下,这可以用作 “真实的” 3D 文本的替代方案。
参见
你可以使用 3D 标签和文本演示项目 查看3D文本的实际效果。
这个页面不会涉及如何在 3D 环境中显示 GUI 场景。有关如何实现这个功能的信息,请参考GUI in 3D 演示项目。
Label3D
Label3D 的行为类似于 Label 节点,只不过是换到了 3D 空间中。与 Label 节点不同,此 Label3D 节点不继承 GUI 主题的属性。不过,外观还是可定制的,使用的也是与 Control 节点相同的字体子资源(包括对 MSDF 字体渲染的支持)。
优势
Label3D 的生成速度比 TextMesh 快。虽然两者都使用缓存机制,只渲染一次新字形,但 Label3D 的(重新)生成速度仍然更快,尤其是对于长文本。这可以避免在低端 CPU 或移动设备上玩游戏时出现卡顿。
Label3D can use bitmap fonts and dynamic fonts (with and without MSDF or mipmaps). This makes it more flexible on that aspect compared to TextMesh, especially for rendering fonts with self-intersecting outlines or colored fonts (emoji).
参见
有关配置字体导入的指南,请参阅 使用字体。
限制
默认情况下,Label3D 与 3D 环境的交互有限。 着色 标志启用时能够接受光照、被光源着色。但是,即使在 Label3D 的 GeometryInstance3D 属性中将 阴影投射 设置为 开启 ,它也不会投射阴影。这是因为该节点内部生成具有透明纹理的四边形网格(每个四边形一个字形),并且具有与 Sprite3D 相同的限制。当多个 Label3D 重叠,尤其是当它们具有轮廓时,透明度排序问题也会变得明显。
这可以将 Label3D 的透明度模式设置为 Alpha Cut 来缓解 ,但代价是文字渲染不够流畅。Opaque Pre-Pass 透明度模式可以保持文本的流畅性,同时允许 Label3D 投射阴影,但仍会存在一些透明度排序问题。
有关详细信息,请参阅 3D 渲染限制页面中的 Transparency sorting 部分。
从远处看Label3D时,文本渲染质量也会受影响。想提升文本渲染质量可参考这些方法,对字体使用mipmap or 切换成MSDF 字体渲染.
TextMesh
TextMesh(文本网格)资源和 Label3D 类似,都能够在 3D 场景中显示文本,使用的是相同的字体子资源。但 TextMesh 生成的不是透明四边形,而是代表字形轮廓的 3D 网格,具有和网格一样的属性。因此,TextMesh 默认是开启着色的,会自动在环境中投射阴影。TextMesh 也可以设置材质(包括自定义着色器)。
这是为网格应用纹理的示例。你可以使用下面的纹理作为生成网格 UV 贴图的参考:
优势
相对于 Label3D 而言,TextMesh 有以下优点:
TextMesh 可以使用纹理来修改文本各个面的颜色。
TextMesh 几何体具有深度,字形看上去是 3D 的。
TextMesh 可以使用自定义的着色器,而 Label3D 无法使用。
限制
TextMesh 的局限性有:
没有内置的轮廓支持,而 Label3D 支持。但是可以使用自定义着色器模拟。
仅支持动态字体(
.ttf
、.otf
、.woff
、.woff2
)。不支持.fnt
和.font
格式的位图字体。无法正确渲染轮廓自相交的字体。如果使用从 Google Fonts 等处下载到的字体时出现渲染问题,请尝试改为从作者的官方网站下载。
对文本进行抗锯齿,需要启用全场景抗锯齿,比如:MSAA,FXAA,Temporal Antialiasing(TAA)。如果未启动抗锯齿,文本会产生颗粒状,尤其是远距离观察时颗粒状更为明显。参考:ref:doc_3d_antialiasing 。
投影 Label 节点(或者其他 Control 节点)
还有最后一种设置起来更麻烦的解决方案,但是灵活性更高:将 2D 节点投影到 3D 空间中。做法是在脚本的 _process()
函数中使用 Camera3D 节点的 unproject_position 的返回值。使用这个返回值来设置 Control 节点的 position
属性。
示例见 3D 路径点演示。
优势
Label、RichTextLabel 等任何 Control 节点,甚至 Button 这样的节点都可以用这种方法。这样就能够实现强大的格式和 GUI 交互。
基于脚本的做法能够在定位方面做到最大的自由度。例如,这样就能够在超出屏幕范围后将 Control 吸附到屏幕的边缘(用于在游戏中实现 3D 标记)。
Control 主题仍然有效。这样实现自定义项目全局的设置就更方便。
限制
投影的 Control 无法以任何形式被 3D 几何体遮挡。目标位置被遮挡时,你可以借助 RayCast 将该控件完全隐藏,但是无法实现位于墙壁后面时只隐藏部分区域的效果。
可以根据距离调整 Control 的
scale
属性,从而调整文本的大小,但是需要手动缩放。Label3D 和 TextMesh 会自动处理,但是灵活性不足(无法设置最小/最大的文本像素大小)。必须在脚本中考虑到分辨率和纵横比的变化,这可能具有挑战性。
我应当使用 Label3D,TextMesh 还是投影的 Control?
在大多数情况下,建议使用 Label3D,因为它更易于设置,并能提供更高的渲染质量(尤其是在禁用 3D 抗锯齿的情况下)。
对于进阶用例,TextMesh 更为灵活,因为它允许使用自定义着色器对文字进行设计。自定义着色器可以修改最终几何图形,例如沿表面弯曲文字。由于文字是实际的三维几何体,因此文字可以选择具有深度,也可以对全局照明做出贡献。
如果你需要 BBCode 或 Control 主题支持等功能,则使用投影 RichTextLabel 节点是唯一的方法。