XRReferenceSpace:getOffsetReferenceSpace() 方法

安全上下文:此功能仅在安全上下文(HTTPS)中可用,在某些或所有支持的浏览器中。

XRReferenceSpace 接口的getOffsetReferenceSpace() 方法返回一个新的参考空间对象,该对象描述了调用该方法的对象与 3D 空间中给定点之间的相对位置差异。如果在XRReferenceSpace 上调用,则getOffsetReferenceSpace() 返回的对象为 XRReferenceSpace;如果在该类型的对象上调用,则返回 XRBoundedReferenceSpace

换句话说,当你在 3D 空间中有一个对象,并且需要相对于该对象放置另一个对象时,你可以调用getOffsetReferenceSpace(),并将你希望第二个对象具有的位置和方向传递给它,相对于你调用getOffsetReferenceSpace() 的对象的位置和方向

然后,在绘制场景时,你可以使用偏移参考空间不仅可以将对象彼此相对定位,还可以应用必要的变换以根据观察者位置正确渲染对象。这在示例根据非 XR 输入实现旋转中进行了演示,该示例演示了一种使用此方法让用户使用鼠标来俯仰和偏航其视角的方法。

语法

js
getOffsetReferenceSpace(originOffset)

参数

originOffset

一个XRRigidTransform,指定新参考空间原点的偏移量。这些值将添加到当前参考空间的位置和方向,然后结果将用作新创建的XRReferenceSpace 的位置和方向。

返回值

一个新的XRReferenceSpace 对象,描述一个参考空间,该空间与调用该方法的参考空间具有相同的本机原点,但具有一个偏移原点,指示对象到由originOffset 给定的点的距离。

如果在你调用此方法的对象是一个XRBoundedReferenceSpace,则返回的对象也是一个。新参考空间的boundsGeometry 设置为原始对象的boundsGeometry,其每个点都乘以originOffset 的逆。

示例

下面是一些示例,展示了如何使用getOffsetReferenceSpace()

传送或设置观察者位置

在首次创建场景时,你可能需要设置用户在 3D 世界中的位置。你可以使用getOffsetReferenceSpace() 来做到这一点。

js
xrSession.requestReferenceSpace("local").then((refSpace) => {
  xrReferenceSpace = refSpace;
  xrReferenceSpace = xrReferenceSpace.getOffsetReferenceSpace(
    new XRRigidTransform(startPosition, { x: 0, y: 0, z: 1.0, w: 1.0 }),
  );
  xrSession.requestAnimationFrame(drawFrame);
});

在此代码中,我们获取一个本地参考空间,然后使用getOffsetReferenceSpace() 创建一个新的空间,其原点调整到由startPosition 给定的位置,其方向正对着 Z 轴。然后使用XRSessionrequestAnimationFrame() 请求第一个动画帧。

根据非 XR 输入实现旋转

WebXR 直接支持的输入控件都是专用的 VR 或 AR 输入设备。为了使用鼠标、键盘或其他输入设备移动或转换 3D 空间中的对象——或允许用户在空间中移动——你需要编写一些代码来读取输入并执行移动。

这是getOffsetReferenceSpace() 的另一个很好的用例。在这个例子中,我们将展示一些代码,让用户通过右键单击并移动鼠标来更改视角。

首先,我们为mousemove 事件添加一个事件处理程序,如果右键按下,则调用我们的代码执行旋转。还要注意,我们设置oncontextmenu 被忽略,方法是在这些事件上调用preventDefault()。这可以防止右键单击导致浏览器中出现上下文菜单。

js
canvas.oncontextmenu = (event) => {
  event.preventDefault();
};
canvas.addEventListener("mousemove", (event) => {
  if (event.buttons & 2) {
    rotateViewBy(event.movementX, event.movementY);
  }
});

接下来,rotateViewBy() 函数根据mousemove 事件中的鼠标增量值更新鼠标观察方向的偏航角和俯仰角。俯仰角受到限制,因此你无法看到正上方和正下方。每次调用此函数时,新的偏移量将用于更新mousePitchmouseYaw 的当前值。

js
let mouseYaw = 0.0;
let mousePitch = 0.0;
const inverseOrientation = quat.create();
const MOUSE_SPEED = 0.003;

function rotateViewBy(dx, dy) {
  mouseYaw += dx * MOUSE_SPEED;
  mousePitch += dy * MOUSE_SPEED;

  if (mousePitch < -Math.PI * 0.5) {
    mousePitch = -Math.PI * 0.5;
  } else if (mousePitch > Math.PI * 0.5) {
    mousePitch = Math.PI * 0.5;
  }
}

最后,我们需要代码来实际将计算出的偏航角和俯仰角应用于观察者的方向。此函数applyMouseMovement() 处理此操作

js
function applyMouseMovement(refSpace) {
  if (!mouseYaw && !mousePitch) {
    return refSpace;
  }

  quat.identity(inverseOrientation);
  quat.rotateX(inverseOrientation, inverseOrientation, -mousePitch);
  quat.rotateY(inverseOrientation, inverseOrientation, -mouseYaw);

  let newTransform = new XRRigidTransform(
    { x: 0, y: 0, z: 0 },
    {
      x: inverseOrientation[0],
      y: inverseOrientation[1],
      z: inverseOrientation[2],
      w: inverseOrientation[3],
    },
  );

  return refSpace.getOffsetReferenceSpace(newTransform);
}

此函数根据当前的俯仰角和偏航角值创建一个反向方向矩阵——用于方向观察者——然后在调用XRRigidTransform() 时使用该矩阵作为方向的来源。然后获取新XRRigidTransform 的参考空间并将其返回给调用方。

这个新的参考空间是观察者位置不变,但其方向已根据从累积的鼠标输入生成的俯仰角和偏航角值改变。applyMouseMovement() 应该在绘制帧时调用,在使用getViewerPose() 获取观察者的姿势之前立即调用,并且应该在此参考空间中执行渲染。

你可以在我们更广泛的 WebXR 教程文章“运动、方向和移动”中看到类似的代码。特别是,查看名为“启动 WebXR 会话”的部分。

规范

规范
WebXR 设备 API
# dom-xrreferencespace-getoffsetreferencespace

浏览器兼容性

BCD 表格仅在启用了 JavaScript 的浏览器中加载。