XRSession: requestAnimationFrame() 方法

可用性有限

此特性不是基线特性,因为它在一些最广泛使用的浏览器中不起作用。

实验性: 这是一项实验性技术
在生产中使用此技术之前,请仔细检查浏览器兼容性表格

安全上下文: 此功能仅在安全上下文(HTTPS)中可用,且支持此功能的浏览器数量有限。

与同名的 Window 方法类似,XRSession 方法 requestAnimationFrame() 会安排一个回调函数,在下次浏览器准备好将会话的虚拟环境绘制到 XR 显示器时执行。指定的 [回调函数](#animationframecallback) 会在下一次重绘之前执行一次;如果您希望它在后续的重绘时执行,您必须再次调用 requestAnimationFrame()。这可以在回调函数内部完成。

回调函数接受两个参数:一个 XRFrame,描述了会话中所有跟踪对象的 [状态](#xrframe);以及一个您可以用于计算任何所需动画更新的时间戳。

您可以通过调用 cancelAnimationFrame() 来取消先前调度的动画。

注意: 尽管这些方法与 Window 接口提供的全局 requestAnimationFrame() 函数有明显的相似之处,但您不得将它们视为可互换的。在沉浸式 XR 会话进行期间,不保证后者能够正常工作。

语法

js
requestAnimationFrame(animationFrameCallback)

参数

animationFrameCallback

在下一次重绘之前调用的函数,以便您根据经过的时间、动画、用户输入更改等来更新和渲染 XR 场景。回调函数接收两个参数作为输入。

时间

一个 DOMHighResTimeStamp,表示从 WebXR 设备接收到更新后的查看器状态的时间偏移量。

xrFrame

一个 XRFrame 对象,描述了会话正在跟踪的对象的 [状态](#xrframe)。这可用于获取查看器和场景本身的姿态,以及渲染 AR 或 VR 场景帧所需的其他信息。

返回值

一个整数值,作为唯一的非零 ID 或句柄,如果您需要删除挂起的动画帧请求,可以将其传递给 cancelAnimationFrame()

示例

以下示例请求使用“inline”模式的 XRSession,以便它可以在 HTML 元素中显示(无需单独的 AR 或 VR 设备)。

注意: 实际应用程序应首先检查设备和用户代理是否支持 WebXR API,然后再通过 XRSystem.isSessionSupported() 检查它们是否都支持所需的会话类型。

js
// Obtain XR object
const XR = navigator.xr;

// Request a new XRSession
XR.requestSession("inline").then((xrSession) => {
  xrSession.requestAnimationFrame((time, xrFrame) => {
    const viewer = xrFrame.getViewerPose(xrReferenceSpace);

    gl.bindFramebuffer(xrWebGLLayer.framebuffer);
    for (const xrView of viewer.views) {
      const xrViewport = xrWebGLLayer.getViewport(xrView);
      gl.viewport(
        xrViewport.x,
        xrViewport.y,
        xrViewport.width,
        xrViewport.height,
      );

      // WebGL draw calls will now be rendered into the appropriate viewport.
    }
  });
});

以下示例直接摘录自规范草案。该示例演示了一种设计模式,可确保通过 Window.requestAnimationFrame 创建的非沉浸式动画与沉浸式 XR 动画之间实现无缝过渡。

js
let xrSession = null;

function onWindowAnimationFrame(time) {
  window.requestAnimationFrame(onWindowAnimationFrame);

  // This may be called while an immersive session is running on some devices,
  // such as a desktop with a tethered headset. To prevent two loops from
  // rendering in parallel, skip drawing in this one until the session ends.
  if (!xrSession) {
    renderFrame(time, null);
  }
}

// The window animation loop can be started immediately upon the page loading.
window.requestAnimationFrame(onWindowAnimationFrame);

function onXRAnimationFrame(time, xrFrame) {
  xrSession.requestAnimationFrame(onXRAnimationFrame);
  renderFrame(time, xrFrame);
}

function renderFrame(time, xrFrame) {
  // Shared rendering logic.
}

// Assumed to be called by a user gesture event elsewhere in code.
function startXRSession() {
  navigator.xr.requestSession("immersive-vr").then((session) => {
    xrSession = session;
    xrSession.addEventListener("end", onXRSessionEnded);
    // Do necessary session setup here.
    // Begin the session's animation loop.
    xrSession.requestAnimationFrame(onXRAnimationFrame);
  });
}

function onXRSessionEnded() {
  xrSession = null;
}

规范

规范
WebXR Device API
# dom-xrsession-requestanimationframe

浏览器兼容性

另见