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) 的实际内容。










