WebXR 中的几何体和参考空间
从根本上讲,在增强现实或虚拟现实环境中用于 WebXR 演示的场景渲染是使用 WebGL 执行的,因此这两个 API 共享许多相同的设计语言。然而,为了能够使用 XR 头戴设备和其他此类设备以真正的 3D 方式呈现场景,WebXR 还有一些必须理解的额外概念。
在本文中,我们将介绍 WebXR 如何扩展 WebGL 的几何图形,以及如何使用空间,特别是参考空间,来描述物体(包括物理物体和虚拟物体)的相对位置和方向。
文章 WebXR 中的空间跟踪 以此处提供的信息为基础,涵盖了用户的头部以及身体其他部位(如手)的物理位置和方向如何映射到数字世界,以及物理和虚拟物体的相对位置如何随着它们的移动而被跟踪,以便正确渲染和合成场景。
3D 几何基础
虽然我们在此将探讨用于计算虚拟空间中物体的位置、方向和运动所需的数学运算,以及将场景的人类观看者整合到其中的必要性,但对几何学以及使用矩阵和向量管理场景 3D 表示的全面介绍远远超出了本文的范围。您可以在 Web 的矩阵数学 中了解更多关于单个操作的信息。
单位
在讨论 WebXR 使用的 3D 空间的几何细节之前,首先了解应用于 3D 世界的度量单位是很有用的。
长度和距离
WebGL 以米为单位测量所有距离和长度。WebXR 继承了此标准,以及世界是一个宽两米、高两米、深两米的立方体的事实。三个轴的最小值均为 -1.0,最大值为 1.0,立方体的中心位于 (0, 0, 0)。
为了您的代码的目的,这个八立方米的空间包含了整个宇宙。您绘制的所有内容都必须将其坐标映射到此空间中,无论是在您的代码中明确映射,还是使用变换来调整所有顶点的坐标。当然,最有效的方法是设计您的对象和代码以使用与 WebGL 相同的坐标系。
WebGL 坐标和长度在渲染时会自动转换为渲染场景的视口大小。
角度
角度使用弧度指定。要将度数转换为弧度,请将度数值乘以 π/180。以下代码片段显示了两个简单的函数,degreesToRadians() 和 radiansToDegrees(),它们在两种角度测量单位之间进行转换。
const RADIANS_PER_DEGREE = Math.PI / 180.0;
let degreesToRadians = (deg) => deg * RADIANS_PER_DEGREE;
let radiansToDegrees = (rad) => rad / RADIANS_PER_DEGREE;
时间和持续时间
注意:出于安全原因,DOMHighResTimeStamp 通常会为时钟引入少量不精确性,以防止其被用于指纹识别和基于时间的攻击。
WebXR 中的所有时间和持续时间都使用 DOMHighResTimeStamp 类型测量,它是一个双精度浮点值,指定相对于起始时间的毫秒时间。由于该值是浮点数,因此根据平台和硬件的不同,其精度可能远高于毫秒级别。
时间主要用于确定自场景上一帧动画绘制以来经过的时间。因此,时间通常与显示器的刷新率对齐,或者如果由于性能问题需要限制帧率,则为刷新率的一部分。这意味着,假设帧率为 60 FPS,时间通常会以 1/60 秒的间隔递进。通过计算,我们发现这意味着每帧理想情况下将间隔 16.6667 毫秒渲染。
使用矩阵的几何运算
我们提供了一份关于 3D 几何相关矩阵数学的指南,包括矩阵如何在渲染 3D 场景时执行的三种主要变换中使用
请注意,当我们说变换应用于一个点时,它也(通过延伸)可以应用于一组点。由于一个对象由空间中的多个点组成的多个多边形表示,因此将相同的变换应用于构成该对象的每个点,将把相同的变换应用于整个对象。变换也可以应用于向量,因为向量是使用坐标值来定义向量的方向和大小来描述的。
关于空间的起源
一个完整的 XR 增强场景——无论是虚拟还是增强——都是由一个到几十个参考帧的组合。场景中每个需要直接与 WebXR 系统交换位置和方向数据的对象,都必须能够以一种可被场景中其他对象理解和适应的方式报告这些信息。
在增强现实 (AR) 中,这是因为需要将虚拟物体插入现实世界,不仅要正确放置它们,还要确保它们不会随着用户视角的改变而自行漂移。在虚拟现实 (VR) 中,这一切都是为了创造一种空间感,其中用户的动作与虚拟显示器上呈现的图像精确匹配,以防止可能导致不适或更糟的分离和脱节。
因此,这一切都关乎创造一种空间感。从 XR 开发人员的角度来看,设计舞台是您的用户最关心的部分。就像建筑师或布景设计师一样,您有能力通过物理环境创造情绪和体验。您如何构建该空间将取决于并影响用户如何与之互动和探索。
注意:一个空间通常具有前景、中景和背景元素。适当的平衡可以创造独特的临场感并引导您的用户。前景包括您可以直接交互的对象和界面。中景包括您可以在一定程度上交互的对象,或者可以接近以更仔细地检查和参与的对象。另一方面,背景通常在很大程度上或完全是非交互的,至少在用户能够接近它并将其带入中景或前景范围之前如此。
在 WebXR 中,空间的基本概念——即场景发生的坐标空间——由 XRSpace 实例表示。空间用于确定用户环境中物体和其他实体(如光源和摄像机)的相对位置和运动。
如前所述,任何给定的 3D 点都由三个分量组成,每个分量标识距空间中心沿三个轴之一的距离。
这是空间原生原点,对应于用户环境中的特定物理位置。每个空间都有自己的原生原点,由 XR 设备的跟踪系统跟踪。这可能与有效原点不同,有效原点是空间局部坐标系的原点。
坐标系的方向性如下图所示
一个名为原点偏移的 XRRigidTransform 用于将点从空间自身的有效坐标系转换到 XR 设备的原生坐标系。原点偏移最初是一个单位变换,因为通常在首次建立空间时,两个原点是对齐的。然而,随着对齐变化随时间积累,原点偏移可能会改变以进行补偿。
空间中点相对于原点的位置由其沿上图中所示的三个空间轴的距离确定。空间原点是点 (0, 0, 0),位于空间的中心和沿每个轴的零位置。具体来说,在初始启动条件下,在查看器对空间的默认方向下
- X 轴水平向右延伸,远离原点,x 坐标为 +1.0 位于世界的右边缘。x 的负值从原点向左延伸,在空间的左边缘达到 -1.0。
- Y 轴正向从原点向上延伸到屏幕顶部,在世界空间的顶部达到 +1.0。y 值小于 0 的位于原点下方,向下延伸到屏幕底部,在世界空间的底部达到 -1.0。
- Z 轴从原点向屏幕外延伸,在该方向上离用户最近的点达到 +1.0。z 的负值从用户向屏幕深处延伸,世界中最远的点 z 为 -1.0。
在最简单的层面上,每个对象都是由 3D 空间中的点和偏移变换定义的一组多边形,指示如何移动和旋转对象以将其定位到空间中所需的位置。如果偏移变换是单位矩阵,则对象位于原点。
然而,为了对空间跟踪和场景几何有用,您需要能够将 XR 设备感知到的位置与空间的坐标系关联起来。这就是参考空间的作用。
参考空间
由于可用的 XR 硬件种类繁多,来自许多开发者的各种外形尺寸,期望开发者必须直接与所使用的跟踪技术通信是不切实际且不可扩展的。相反,WebXR Device API 的设计是为了让开发者规划用户的体验并请求最能代表这些需求的适当参考空间。这是通过向用户代理请求匹配这些需求的 XRReferenceSpace 来完成的。
XRReferenceSpace 对象充当将一个坐标系参考帧调整到另一个坐标系参考帧的手段。戴上头显后,假设您周围的虚拟世界有一个坐标系,其中您的位置是 (0, 0, 0)——也就是说,您处于一切的中心。这难道不令人感到振奋吗?前方,直接在您的头显前面,是 -Z 轴,+Z 在您身后。X 轴正向在您的右侧,负向在您的左侧。Y 轴在您向下移动时为负,在您向上移动时为正。这表示在您开始使用 XR 系统时头显在空间中的位置,原点 (0, 0, 0) 大致位于您的鼻梁处。这个空间是世界空间。
接下来,考虑您左手中的 XR 控制器。它能够报告移动和方向,但它对头戴设备的位置或更重要的是其坐标系一无所知。但控制器仍然需要一种方式向您的应用程序报告其位置。因此,它有自己的坐标系。当输入事件发生时,这个参考空间会提供给您的应用程序。这个参考空间内部知道如何将控制器的坐标映射到头戴设备的坐标,因此 WebXR 可以为您来回转换坐标。
一旦创建,XRReferenceSpace 就保证了一定程度的运动和方向跟踪支持,并提供了一种获取 XRViewerPose 的机制,从中您可以获得一个矩阵,该矩阵表示该空间相对于世界空间的位置和朝向方向,如果该空间代表一个观察者(例如用户的头戴设备、观察者的头戴设备或虚拟摄像机)。
所有这些都是浏览器的责任,它提供一致的行为,无论底层参考空间的能力如何。无论单个 XR 设备多么强大或简单,使用 WebXR 编写的代码仍然可以在可用硬件的限制下工作。
无论您选择哪种参考空间类型,其类型都是 XRReferenceSpace 或派生自 XRReferenceSpace 的类型。当前可用的参考空间类型如下所示。
有界地板-
一个
XRBoundedReferenceSpace,类似于local类型,但用户预计不会超出由返回对象中的boundsGeometry给出的预定边界。 local-
一个
XRReferenceSpace跟踪空间,其原生原点位于会话创建时观看者位置附近。确切位置取决于底层平台和实现。用户预计不会超出其起始位置移动太多,跟踪针对此用例进行了优化。对于具有六个自由度 (6DoF) 跟踪的设备,local参考空间尝试使原点相对于环境保持稳定。 局部地板-
一个
XRReferenceSpace,类似于local类型,只是起始位置被放置在查看器可以站立的安全位置,其中 Y 轴的值在地面高度为 0。如果地面高度未知,则用户代理将估算地面高度。如果估算的地面高度不为零,浏览器应将其四舍五入以避免指纹识别(可能四舍五入到最近的厘米)。 无界-
一个
XRReferenceSpace跟踪空间,允许用户完全自由移动,可能在距离其原点极远的距离上移动。查看器根本不被跟踪;跟踪针对用户当前位置周围的稳定性进行了优化,因此原生原点可能根据需要漂移以适应这一需求。 查看器-
一个
XRReferenceSpace跟踪空间,其原生原点跟踪观看者的位置和方向。这用于用户可以物理移动的环境,并且所有XRSession实例都支持它,包括沉浸式和内联式,尽管它对内联式会话最有用。它在确定观看者和输入之间的距离,或在处理偏移空间时特别有用。否则,通常会更频繁地使用其他参考空间类型之一。
本指南的其余部分将探讨如何为您的应用程序需求选择正确的参考空间。
使用参考空间定义空间关系
有许多常用的方法来参考物体相对于其环境的位置和方向,以及约束环境本身。为此,WebXR 定义了一组标准空间,称为参考空间,每个空间都支持不同的技术,用于将其局部空间的参考帧坐标系与其所在空间的坐标系相关联。
但是,无论使用哪种类型的参考空间,您都可以使用相同的函数将坐标从一个空间转换到父空间。
选择参考空间类型
首先,让我们陈述决定使用哪种参考类型过程中最简单的一步:您最可能使用的参考空间是 local、local-floor、unbounded 或 bounded-floor。
地板级别参考空间
名称中带有 -floor 的参考空间类型的工作方式与相应的非地板空间相同,只是它们尝试自动确保查看器位于地面水平或附近(但始终高于地面)的安全位置。这是 y 坐标始终为 0 的平面,除非另行建立地板。如果房间的地板不平坦或地板高度高于地面水平不同,这些空间类型则不可行,因为它们不支持化身垂直位置的变化。
主要参考空间类型
viewer 参考空间对应于查看器在空间中的位置;它由 XRFrame 方法 getViewerPose() 返回的 XRViewerPose 使用。通常情况下,它不会直接用于其他用途。唯一的真正例外是,当您在网页内容中内联执行 XR 场景时,您很可能会使用 viewer 参考空间。
local 参考空间通常用于描述一个相对较小的区域,例如单个房间。它不仅在使用沉浸式会话模式(immersive-vr 或 immersive-ar)时始终可用,而且在请求新会话时始终包含在可选功能中;因此,通过 navigator.xr.requestSession() 创建的每个会话都支持 local 参考空间类型。
要表示一个大面积区域——可能涉及多个房间或更远——您可以使用 unbounded 参考空间类型,它不对观看者的移动施加任何限制。如果您希望阻止用户进入某些区域,则必须自行处理。
bounded-floor 参考空间类型没有对应的非地板边界类型。如果用户的 XR 硬件允许他们在现实世界空间中移动,并且您能够这样做,那么使用 bounded-floor 参考空间可能会很有用,它允许您明确定义允许和安全的通行区域的边界。有关有界参考空间使用的更多信息,请参阅文章 使用有界参考空间。
通过使用参考空间来描述物体的位置和方向,WebXR 能够标准化您用于描述这些数据的数据形式,无论底层 XR 硬件如何。然后,参考空间的配置能够为您提供正确渲染空间内容所需的视图矩阵和对象姿态。
建立参考空间
最顶层的空间——通过调用 XRSession 方法 requestReferenceSpace() 获得的空间——描述了用于整个世界空间的坐标系。一切都与这个坐标系基本相关,它代表了用户设备位置与虚拟世界之间的关系。
虽然您可以将 WebXR 用于从世界增强注释到 360° 视频播放,再到科学模拟,再到虚拟现实训练系统,或者任何您可以想象到的其他事物,但让我们以 3D 视频游戏为例,作为典型的 WebXR 应用程序。考虑玩家角色站在游戏世界空间中的模型。您使用世界参考空间定义的坐标系来定位该角色。
要将玩家移动到新位置,您可以重写所有坐标,或者每次移动时手动应用变换,但有一个更简单的方法,这要归功于参考空间及其彼此相对创建的能力。创建一个 XRRigidTransform 对象,表示玩家角色的新位置和方向,然后使用 XRReferenceSpace 方法 getOffsetReferenceSpace() 创建一个新的参考空间来表示角色在新位置的视角。这在实现支持使用键盘或鼠标等非 XR 设备来移动玩家角色时特别方便。
有了新创建的参考空间,角色可以保持在相同的坐标处,但在世界中看起来位于新位置(并从新位置的角度看世界)。有关如何使用参考空间管理玩家视角的更详细信息,请参阅文章
在我们的游戏头像示例中,头像(或任何其他移动的生物或机器)很少是简单地在世界中滑动的块状物。它们通常具有额外的形状以及内部运动,例如移动的腿、走路时摆动的手臂、转动或晃动的头部、四处移动的武器等等。使用标准的 WebGL 技术和定位矩阵或 XRRigidTransform 来将这些对象移动到相对于有效原点的正确位置,从而使它们栩栩如生。
参考空间设备限制
某些 XR 设备无法支持给定体验,尽管 API 努力弥补任何缺失的功能。例如,对于像 GearVR 设备这样的基本头戴设备,无法使其在需要支持用户通过跟踪其真实世界运动来在环境中行走的应用中工作。
为了支持渐进增强——从而扩大您的应用程序或站点的可用性——您应该选择提供最低所需功能的参考空间,或者提供一种回退机制,检测获取参考空间失败的尝试,并尝试使用功能较弱的替代方案。
出现的兼容性问题可能非常基础,例如在仅支持 VR 的头戴设备上无法支持 immersive-ar 模式(增强现实会话),或者可能涉及请求一个或多个在尝试创建 XR 会话时无法满足的必需选项。
XR 会话是使用 navigator.xr.requestSession() 方法创建的。它的一个可选参数是一个对象,您可以使用它来指定会话必须(或理想情况下应)支持的必需和/或可选功能。目前,唯一支持的选项是标识标准参考空间的字符串。通过使用这些,您甚至可以在代码运行之前确保您可以访问支持您所需或首选参考空间类型的 WebXR 会话。
注意:目前,要使用或首选的参考空间是创建 XRSession 时唯一可用的选项。未来,可能会有更多选项可用。
定位和定向物体
应用程序和 WebXR API 之间交换的所有空间(位置、方向和运动)信息都与帧渲染时的一个特定空间相关。任何进一步的位置和方向管理都在您和 WebGL 之间,尽管您确实使用了参考空间的原点偏移,以便在 3D 世界中正确放置对象。
当需要渲染动画帧时,调用 WebXR 会话的 XRSession 对象的 requestAnimationFrame() 方法时指定的 callback 函数会被调用。callback 函数会接收一个参数,指示帧发生的时间,并且应该执行相应动画帧的所有渲染。
随着 callback 函数以递增的时间值重复调用,callback 函数生成一系列帧,这些帧使用 XR 硬件呈现,从而向用户显示 3D 场景。
您可以在文章 渲染和 WebXR 帧动画回调 中了解更多关于动画过程的信息。
有关在虚拟空间中定位、定向和移动对象的示例以及更详细的代码级解释,请参阅文章 移动、方向和运动。