WebXR 是浏览器原生支持 vr/ar 的稳定 API,需 https/localhost、用户手势触发 requestsession,并通过 isSessionSupported 检测兼容性;渲染依赖 webgl/Three.js,须正确配置 XRSession、renderState、referenceSpace 及控制器。

WebXR 是浏览器原生支持 VR/AR 应用的 API,不是第三方库,也不依赖插件;它已进入稳定阶段,chrome、edge、firefox(部分支持)均可用,但必须通过 HTTPS 或 localhost 访问,否则 navigator.xr 为 undefined。
如何检测和请求 WebXR 支持
不能只靠 "xr" in navigator 判断——有些浏览器暴露 navigator.xr 但不支持任何 XRSessionMode。真实检测要发起一次 session 请求并监听拒绝原因。
- 先检查
navigator.xr是否存在且为对象 - 再调用
navigator.xr.isSessionSupported("immersive-vr")(返回 promise),而不是直接requestSession - 若拒绝,常见错误是:
SecurityError(非 HTTPS)、NotSupportedError(设备无 VR 硬件或浏览器未启用 WebXR)、NotAllowedError(用户未点击触发,如自动启动)
if ("xr" in navigator) { navigator.xr.isSessionSupported("immersive-vr").then(supported => { if (supported) { // 可安全调用 requestSession } }).catch(err => console.error("XR 检测失败:", err.name)); }
如何创建并渲染一个基础 VR 场景
WebXR 不负责 3D 渲染,它只提供姿态、视图、投影矩阵;你得自己接 WebGL 或 Three.js。核心是绑定 XRSession 的 render 循环,并在每一帧中调用 getViewerPose 获取头部位置。
-
requestSession("immersive-vr")必须由用户手势(如click、touchstart)触发 - 拿到 session 后,需调用
session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) }),否则requestAnimationFrame中无法获取有效视图 - 每一帧内必须调用
session.requestAnimationFrame(不是window.requestAnimationFrame),否则姿态更新会不同步
button.addEventListener("click", async () => { const session = await navigator.xr.requestSession("immersive-vr"); session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) }); function render(time, frame) { const pose = frame.getViewerPose(referenceSpace); if (pose) { for (const view of pose.views) { // 使用 view.transform、view.projectionMatrix 渲染左右眼 } } session.requestAnimationFrame(render); } session.requestAnimationFrame(render); });
Three.js + WebXR 的最小可行配置
Three.js r125+ 内置 WebXR 支持,但默认不启用——必须手动开启渲染器的 xr.enabled 并添加 XRControllerModelFactory 才能有手柄模型。漏掉任一环节都会导致黑屏或无交互。
立即学习“Java免费学习笔记(深入)”;
- 渲染器初始化后立即设
renderer.xr.enabled = true - 场景中必须添加
new THREE.XRController(0)和new THREE.XRController(1)(对应左右手),否则手柄输入不可用 - 若用
OrbitControls,需在进入 XR 时禁用,否则视角会被双重控制 - 加载 GLB 模型时,确保使用
THREE.GLTFLoader并启用dracoLoader,否则复杂模型在 VR 中易卡顿
const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.xr.enabled = true; const controller1 = renderer.xr.getController(0); const controller2 = renderer.xr.getController(1); scene.add(controller1, controller2); // 进入 VR 前 button.addEventListener("click", () => { renderer.xr.setSession(session); // session 来自 requestSession });
WebXR 的坑不在 API 复杂,而在环境链路太长:HTTPS → 浏览器标志位 → 设备驱动 → WebGL 上下文 → 三维引擎适配。任一环节断开,错误信息都极不明确,比如 getViewerPose 返回 NULL 可能是 reference space 未正确创建,也可能是 session 被意外 ended,调试时优先检查 session.visibilityState 和 console.log(frame) 的实际内容。