WebXR 是一组支持将渲染 3D 场景用来呈现虚拟世界(虚拟现实,也称作VR)或将图形图像添加到现实世界(增强现实,也称作AR)的标准。 通过该 API 可以访问 VR/AR 虚拟设备和跟踪用户姿态动作。它用于替换已经废弃的 WebVR API。
Khronos 的 OpenXR API 基本覆盖了 WebXR API 基础功能,但是它们与 WebGL 和 OpenGL 的关系不同,WebGL 和 OpenGL 关系是 1:1 的映射,而 WebXR 和 OpenXR 是由两个不同的组织开发,所以它们之间会有一些相同概念用不同的方式来表示。
- AR 全称 Augmented Reality,增强现实。可以让屏幕上的虚拟世界能够与现实世界场景进行结合与交互。可以参考游戏 Pokémon GO。
- VR 全称 Virtual Reality,虚拟现实。由电脑创建虚拟的 3D 世界,用户看不到现实环境,完全沉浸在虚拟世界中。可以参考电影 头号玩家。
- MR 全称 Mixed Reality,混合现实。可以看成 AR 和 VR 的融合,用户可以看见现实环境,和额外的虚拟物件,并可以进行交互。可以参考 Quest 的 MR 头盔。
- XR 全称 Extended Reality,扩展现实。它是一个总称,任何虚拟和现实等技术,如 AR、VR 和 MR 都可以看成 XR 的一部分。
WebXR 中的 X 并不是作为首字母缩略词的一部分,而是作为某种代数变量来表示,你可以将它看成任何你希望的词,例如 Extended 或 Cross。
历史
在 2014 年,Mozilla 工程总监 Vladimir Vukicevic 首次提出 WebVR 概念,它可以兼容PC、移动设备、VR等各种设备,无需下载和安装在浏览器即可运行 3D VR 内容。
Mozilla 提出 WebVR 后,谷歌 Chrome 团队在 2016 年也加入开发,合作推出了 WebVR API 1.0。后来部分微软员工也加入,帮助完善 WebVR API 2.0。
到了 2018 年,谷歌、Mozilla等巨头组成的 W3C Immersive Web Working Group,推动标准化 WebXR 取代 WebVR,它被设计整合 AR、VR 以及未来可能出现的现实和设备。
兼容性
目前 WebXR 并没有正式发布,支持 WebXR 的浏览器并不多,如下所示。
可以发现不是完全不支持就是需要通过实验 flag 来开启该功能,只有少数几个浏览器才支持,不过没有关系,WebXR 主要用在 VR 头盔设备上,而头盔浏览器一般都是支持 WebXR 的,例如 Firefox Reality 浏览器。
目前 Firefox Reality 浏览器已经交给了 Igalia 继续开发,Igalia 基于 Firefox Reality 继续开发新的 Wolvic 浏览器 。Mozilla 则并将业务重心转向 Web VR 社交平台 Hubs 。
快速体验
要将画面渲染到 VR 设备上,需要搭配使用 WebXR 和 WebGL API,WebXR 负责访问 VR 设备和获取传感器数据,WebGL 负责渲染画面。
要最简单的将画面渲染到 VR 设备上需要以下几步。
- 检查当前环境是否支持 WebXR
- 创建 XR Session
- 创建 XR 兼容的 WebGLContext
- 在 XRSession 的 requestAnimationFrame 回调中不断的渲染新的一帧画面
- 用户退出或自己结束 XRSession
下面代码演示如何创建一个最简单的 VR 场景。
if (navigator.xr) {
// 1. 检查是否支持 immersive-vr 模式
navigator.xr.isSessionSupported('immersive-vr').then((supported) => {
if (supported) {
const btn = document.createElement('button')
btn.textContent = '进入 VR'
btn.onclick = onBtnClick
document.body.appendChild(btn)
}
});
}
let gl
function onBtnClick() {
navigator.xr.requestSession('immersive-vr').then(session => {
// 2. 请求 VR 会话
const canvas = document.createElement('canvas');
gl = canvas.getContext('webgl', { xrCompatible: true });
// 3. 与创建普通 WebGL 不同,这里需要设置 xrCompatible 参数
session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) });
// 更新会话的渲染层,后续渲染会渲染在该层上
session.requestAnimationFrame(onXRFrame);
})
}
function onXRFrame(time, frame) {
const session = frame.session;
// 4. 这个 session 是上面请求的 session
// 需要使用 session 上的 requestAnimationFrame
// 而不是 window 上的
session.requestAnimationFrame(onXRFrame);
const glLayer = session.renderState.baseLayer;
// 绑定 framebuffer
gl.bindFramebuffer(gl.FRAMEBUFFER, glLayer.framebuffer);
// 随着时间变化清除色
gl.clearColor(Math.cos(time / 2000),
Math.cos(time / 4000),
Math.cos(time / 6000), 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
}
navigator.xr
是 WebXR 的入口,它是一个 XRSystem 对象,它只有两个方法,isSessionSupported
检查目标模式是否支持和 requestSession
请求目标模式会话。模式分为 ar 和 vr。
首先需要通过 isSessionSupported
方法检测是否支持目标模式,如果支持就可以提示用户可以进入 VR 模式。这里不能直接进入 VR 会话,需要在用户交互的回调函数中请求进入,类似于音频的自动播放限制。
用户点击按钮后,就可以通过 requestSession
方法请求目标模式的 XRSession,有了 XRSession 后,需要给它设置一个渲染层,后续渲染的画面会渲染到该渲染层上,和创建 WebGL 上下文一样,这里通过 canvas 元素的 getContext
方法获取,唯一不同的是需要传入 xrCompatible
参数,让 GL 上下文由 XR 适配器创建,这样才能与 XR 兼容。
最后就是利用 XRSession 上的 requestAnimationFrame
方法来渲染画面到 VR 设备。与 window.requestAnimationFrame
类似,不过它多接收一个 XRFrame 参数,上面保存了这一帧的信息,接下来渲染和 WebGL 中是一样的,不过需要将画面渲染到 XRSession 渲染层的 framebuffer
中。
要运行上面这个 Demo 会非常困难,在桌面浏览器中不支持 VR,需要一个 VR 头盔设备,另外 WebXR 还需要 https 环境。
不过可以安装 WebXR 模拟器插件来调试开发 XR 应用,下图是在安装 XR 插件后,运行在 Chrome 浏览器中的效果。