面向 WebXR 开发者的透视回顾
因为 WebXR 使用 WebGL 来渲染使用 XR 硬件显示的 3D 环境的视图,所以很容易认为透视相关的方面与任何 WebGL 项目中的方面相同。这在很大程度上是正确的,但有一些特定的主题需要重新审视,还需要考虑一些次要的额外指南,以确保你的应用程序看起来正确,更重要的是,你的 3D 世界不会导致人们因眩晕或其他可能由于所见内容与大脑对现实的预期不符而引起的效应而感到不适。
在本文中,我们将探讨项目计算、应用和考虑透视方式可能与为非 XR 应用程序编写的代码不同的场景。
视锥体问题
每个 WebXR 会话,由一个 XRSession
对象表示,都提供了一组可以通过创建一个新的 XRRenderState
对象来配置的选项,并通过调用会话的 updateRenderState()
方法来激活更新后的状态,以替换当前配置。
这些值中的大多数定义了 XR 设备的 视锥体;也就是说,应该渲染的设备视觉范围的子集。视锥体可以使用四个关键数据点来表示:视场角、渲染图像的 纵横比 以及近剪裁平面和远剪裁平面的距离。
欢迎来到投影矩阵
大多数情况下,您将使用的投影模型是透视投影模型,因此其投影矩阵称为**透视投影矩阵**。此矩阵用于将 3D 虚拟世界中的每个像素映射到正在渲染的视图的 2D 后备缓冲区中的一个点。
在正常情况下,您可以也应该直接从您正在渲染的视图中获取透视投影矩阵。 XRView
对象的 projectionMatrix
属性包含表示视图透视的投影矩阵,并且几乎始终应该在不更改的情况下使用。对 XRView
提供的投影矩阵所做的更改可能会导致渲染内容相对于现实世界场景的失真或对齐不良;这可能足以导致至少一些用户的 虚拟现实病。
例如,如果您的应用程序使用名为 uProjectionMatrix
的 WebGL 统一变量将投影矩阵传递给您的着色器,您可能会使用类似以下代码来传递当前正在渲染的 view
的投影矩阵
gl.uniformMatrix4fv(uProjectionMatrix, false, view.projectionMatrix);
自定义投影矩阵
虽然通常应该避免手动构建或更改视图提供的投影矩阵,但在某些情况下可以这样做。最常见的理由可能是为了更改近剪裁平面和远剪裁平面的距离以出于性能原因增加或减少要渲染的多边形数量。当游戏提供调整观看距离的偏好设置时,这是通过更改这些平面距离值来实现的。
在沉浸模式下,WebXR 系统从硬件供应商提供的软件中获取默认的 视锥体。此视锥体基于设备镜头、显示硬件和摄像头的某种组合。从成像传感器的尺寸到镜头的焦距,所有内容都参与了此计算。
沉浸式体验使用硬件定义的视场、焦距等,因此在使用沉浸式会话时,您只能更改近剪裁平面和远剪裁平面的距离。这是通过设置 XRRenderState
属性 depthNear
和 depthFar
的值来实现的。
在内联模式下,您还可以通过设置 renderState
的 inlineVerticalFieldOfView
属性的值来直接更改视场。此属性需要设置为任何沉浸式会话的 null
。
获得视锥体后,您可以使用类似以下函数计算 WebGL 在渲染场景时使用的透视投影矩阵
function makePerspectiveMatrix(fieldOfViewInRadians, aspectRatio, near, far) {
const f = 1.0 / Math.tan(fieldOfViewInRadians / 2);
const rangeInv = 1 / (near - far);
return [
f / aspectRatio,
0,
0,
0,
0,
f,
0,
0,
0,
0,
(near + far) * rangeInv,
-1,
0,
0,
near * far * rangeInv * 2,
0,
];
}
near
和 far
的值直接从视锥体获得;它们分别是原点到近剪裁平面最近点和远剪裁平面的距离。纵横比是通过将视场的宽度除以其高度获得的值。如果目标显示器使用 16:9 的纵横比,则用于 aspectRatio
的值应为 16/9
或 1.7777777778。
如果您使用的是提供矩阵数学函数的库或框架,它几乎肯定会包含类似的函数。例如,在流行的 glMatrix 库中,您会在 mat4.perspective()
函数中找到它。
无论来自哪里,一旦您获得了投影矩阵,您就可以在调用 WebGL 渲染场景时使用它。
与现实对齐
在增强现实 (AR) 应用程序中,您渲染的内容叠加在现实世界之上。为了做到这一点,您的透视计算需要与查看者对周围世界的透视相匹配。如果您没有做到这一点,您的对象将无法与现实正确对齐。
如果您的虚拟相机的透视投影矩阵没有导致虚拟对象具有与现实世界相同的表观透视,那么虚拟世界和物理世界之间的脱节可能会令人震惊,甚至更糟的是,会导致您的应用程序的用户产生眩晕、晕动症或其他形式的不适。
另一个相关问题是,如果您使用透视矩阵来确定放置对象的位置,那么透视投影矩阵与用户对世界的物理透视之间的不匹配可能会导致对象没有被准确地定位。例如,如果您的应用程序允许用户在其墙上悬挂虚拟画作,但透视矩阵不匹配,则放置的画作可能会最终没有真正靠在墙上,部分与墙相交,或者一端比另一端更靠近墙,而不是与墙平行。