首页
/ three.js ARButton 使用指南:基于 WebXR 快速构建沉浸式 AR 会话启动按钮

three.js ARButton 使用指南:基于 WebXR 快速构建沉浸式 AR 会话启动按钮

2026-09-05 10:11:22作者:裘旻烁

本文围绕 three.js 官方 API 文档 docs/pages/ARButton.html.md 展开,系统讲解 ARButton 这个 WebXR 辅助类的作用、导入方式与 createButton 工厂方法的参数语义,并结合仓库源码 examples/jsm/webxr/ARButton.js 逐段剖析按钮的内部状态机:WebXR 能力探测、immersive-ar 会话的启动与结束、dom-overlay 自动注入、offerSession 系统级唤起,以及 HTTPS 等前置约束。读完后,你可以在自己的 three.js 应用中一行代码接入 AR 入口,并能针对 hit-test、plane-detection、camera-access 等 WebXR 特性按需配置会话参数。

ARButton 是什么

ARButton 是一个用于创建“启动沉浸式 AR 会话按钮”的工具类。它的官方定义直接写在源码头部注释中:

// examples/jsm/webxr/ARButton.js
/**
 * A utility class for creating a button that allows to initiate
 * immersive AR sessions based on WebXR. The button can be created
 * with a factory method and then appended to the website's DOM.
 *
 * ```js
 * document.body.appendChild( ARButton.createButton( renderer ) );
 * ```
 */

它的定位非常聚焦:

  • 只负责发起 immersive-ar 这一种 WebXR 会话模式(区别于 VRButtonimmersive-vr,也区别于 XRButton 的“先 AR 后 VR”回退策略,见 docs/pages/XRButton.html.md);
  • 自动完成能力探测、按钮样式、会话生命周期管理,把 WebXR 原始 API 的样板代码封装起来;
  • 工厂方法(静态方法)形式返回一个 HTMLElement,由开发者自行挂载到页面 DOM。

它是 three.js 的 addon(插件),不属于核心包 three 本体,必须显式导入。

导入方式

按照文档要求,ARButton 需要从 addons 路径显式导入:

import { ARButton } from 'three/addons/webxr/ARButton.js';

该模块由 examples/jsm/Addons.js 统一再导出,仓库中所有 AR 示例(如 examples/webxr_ar_hittest.html)都通过 import map 把 three/addons/ 映射到 ./jsm/ 目录来解析这个路径。

基本用法:一行代码创建按钮

文档给出的最小可运行示例:

document.body.appendChild( ARButton.createButton( renderer ) );

在 AR 场景里,这行代码通常与以下三处配套代码一起出现。以 examples/webxr_ar_cones.html 为例,AR 会话中相机画面由设备透传提供,因此渲染器必须带透明背景:

const renderer = new THREE.WebGLRenderer( { antialias: true, alpha: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setAnimationLoop( animate );
renderer.xr.enabled = true;            // 开启 XR 渲染路径
container.appendChild( renderer.domElement );

document.body.appendChild( ARButton.createButton( renderer ) );

两个关键前提值得强调:

  1. renderer.xr.enabled = true:按钮启动会话后调用的是 renderer.xr.setSession( session ),若未启用 XR 路径,渲染不会接管 XR 帧循环;
  2. renderer 使用 setAnimationLoop 而非 requestAnimationFrame:XR 会话下必须由浏览器在 XR 帧边界内回调,three.js 的动画循环接口正好满足这一点;
  3. alpha: true:让 WebGL 画布透明,AR 透视画面(由系统合成在底层)才能透出。

API 详解:.createButton( renderer, sessionInit )

文档定义的静态方法签名为:

.createButton( renderer : WebGLRenderer | WebGPURenderer, sessionInit : XRSessionInit ) : HTMLElement

参数 renderer

渲染器实例,WebGLRendererWebGPURenderer 均可。按钮内部通过它调用 renderer.xr(即 WebXRManager)完成会话接管,见 examples/jsm/webxr/ARButton.js 中的 onSessionStarted

async function onSessionStarted( session ) {

    session.addEventListener( 'end', onSessionEnded );

    renderer.xr.setReferenceSpaceType( 'local' );

    await renderer.xr.setSession( session );

    button.textContent = 'STOP AR';
    sessionInit.domOverlay.root.style.display = '';

    currentSession = session;

}

注意 ARButton 固定使用 local 参考空间local 表示以会话启动时用户头部位置为原点——这正是 AR 场景的合理选择(不依赖房间平面标定)。WebXRManager.setReferenceSpaceType 的实现位于 src/renderers/webxr/WebXRManager.js,且该方法明确说明“不能在进行中的 XR 会话里调用”,所以 ARButton 把它放在 setSession 之前执行。

参数 sessionInit

这是透传给 WebXR 标准的 XRSessionInit 配置对象,第二个参数可省略(默认 {})。它对会话能力的控制方式与浏览器原生 navigator.xr.requestSession 完全一致,仓库中的四个示例分别演示了典型用法:

// 命中测试:requiredFeatures 表示会话必须支持该特性,否则请求失败
// examples/webxr_ar_hittest.html
document.body.appendChild( ARButton.createButton( renderer, { requiredFeatures: [ 'hit-test' ] } ) );

// 平面检测
// examples/webxr_ar_plane_detection.html
document.body.appendChild( ARButton.createButton( renderer, {
    requiredFeatures: [ 'plane-detection' ]
} ) );

// 相机画面访问
// examples/webxr_ar_camera_access.html
document.body.appendChild( ARButton.createButton( renderer, { requiredFeatures: [ 'camera-access' ] } ) );

// 光照估计:optionalFeatures 表示尽量支持,不支持也不报错
// examples/webxr_ar_lighting.html
document.body.appendChild( ARButton.createButton( renderer, { optionalFeatures: [ 'light-estimation' ] } ) );

返回值语义

文档写明返回值是“按钮本体,或者在 immersive-ar 不被支持时的错误信息”。从源码看,实际可能出现五种界面状态,这决定了你不应假设返回的永远是可点击按钮:

状态文本 触发条件 源码位置
START AR 设备支持 immersive-ar,可点击启动 examples/jsm/webxr/ARButton.js
STOP AR 会话进行中,点击结束会话 examples/jsm/webxr/ARButton.js
AR NOT SUPPORTED isSessionSupported('immersive-ar') 返回 false,按钮被禁用 examples/jsm/webxr/ARButton.js
AR NOT ALLOWED 调用 isSessionSupported 抛出异常(如权限被拒) examples/jsm/webxr/ARButton.js
WEBXR NEEDS HTTPS / WEBXR NOT AVAILABLE 环境中不存在 navigator.xr(非安全上下文时返回带 HTTPS 地址的链接) examples/jsm/webxr/ARButton.js

最后一个状态揭示了 AR 的硬性部署前提:WebXR 仅在安全上下文(HTTPS 或 localhost)下暴露。源码中检测到 window.isSecureContext === false 时会生成一个指向对应 HTTPS 地址的 <a> 元素作为提示。因此在本地开发时必须走 localhost,生产部署必须配置 HTTPS。

内部工作流程剖析

结合 examples/jsm/webxr/ARButton.js 的完整实现,按钮的完整生命周期如下。

1. 能力探测与初始渲染

createButton 创建 <button> 后立即执行 stylizeElement(绝对定位、距底部 20px、半透明白色文字等内联样式,见 examples/jsm/webxr/ARButton.js),然后分两条路径:

if ( 'xr' in navigator ) {

    navigator.xr.isSessionSupported( 'immersive-ar' ).then( function ( supported ) {

        supported ? showStartAR() : showARNotSupported();

    } ).catch( showARNotAllowed );

    return button;

} else {
    // 返回 'WEBXR NOT AVAILABLE' / 'WEBXR NEEDS HTTPS' 提示链接
}

注意按钮初始 display: 'none',只有 isSessionSupported 返回 true 后才会显示为可点击的 START AR。也就是说页面加载后按钮可能一直不出现,这是设计使然而非 bug。

2. dom-overlay 的自动注入与关闭按钮

AR 会话进入后浏览器通常隐藏全部网页 DOM。ARButton 在首次展示 START AR 时(showStartAR)会检测 sessionInit.domOverlay 是否已配置,若没有则自动:

  1. 创建一个隐藏的 <div> overlay 容器并追加到 document.body
  2. 在其中生成一个 38×38 的 SVG 白色 “×” 图标,绝对定位在屏幕右上角(right: 20px; top: 20px),点击它即调用 currentSession.end() 退出 AR;
  3. sessionInit.optionalFeatures 推入 'dom-overlay',并写入 sessionInit.domOverlay = { root: overlay }
// examples/jsm/webxr/ARButton.js(showStartAR 节选)
if ( sessionInit.domOverlay === undefined ) {

    const overlay = document.createElement( 'div' );
    overlay.style.display = 'none';
    document.body.appendChild( overlay );

    const svg = document.createElementNS( 'http://www.w3.org/2000/svg', 'svg' );
    // ... 右上角 “×” 图标,点击后 currentSession.end()

    if ( sessionInit.optionalFeatures === undefined ) {

        sessionInit.optionalFeatures = [];

    }

    sessionInit.optionalFeatures.push( 'dom-overlay' );
    sessionInit.domOverlay = { root: overlay };

}

这一机制有两个使用上的注意点:

  • 直接修改了你传入的 sessionInit 对象(给 optionalFeatures 数组追加元素、补上 domOverlay 字段)。如果你把同一个配置对象复用到其他逻辑,要意识到它已被增强;
  • 因为 dom-overlay 是通过 optionalFeatures 请求的,不支持该特性的设备不会导致会话失败,只是失去右上角关闭入口。会话进行中通过 sessionInit.domOverlay.root.style.display = '' 显示 overlay,结束后恢复隐藏(examples/jsm/webxr/ARButton.js)。

3. offerSession:系统级免点击唤起

ARButton 还利用了 WebXR 的 offerSession API:在展示 START AR 时,若 navigator.xr.offerSession !== undefined,会主动向浏览器“推销”一次 AR 会话请求;用户若在系统层面接受,无需点击网页按钮即可直接走 onSessionStarted 流程。会话结束后再次点击时也会先 end() 旧会话、再 offerSession 发起新一轮(examples/jsm/webxr/ARButton.js)。该 API 为可选能力,未实现时自动降级为纯点击启动,代码对两种情况都做了兼容。

4. 会话生命周期:onSessionStarted / onSessionEnded

会话状态切换的闭环逻辑:

  • 启动:监听 end 事件 → 设置 local 参考空间 → await renderer.xr.setSession( session ) → 按钮文案切换为 STOP AR、显示 overlay;
  • 结束:移除监听 → 文案恢复 START AR、隐藏 overlay、currentSession 置空,按钮重新具备再次启动的能力。

STOP AR 的点击路径(currentSession !== null 分支)会主动调用 currentSession.end(),随后由 end 事件驱动收尾,避免状态不同步。

仓库中的实际应用场景

仓库里五个 AR 示例覆盖了 ARButton 的典型组合,可直接作为业务模板参考:

示例 配置要点 用途
examples/webxr_ar_cones.html 无额外特性 最简 AR 场景,透传画面上摆放锥体
examples/webxr_ar_hittest.html requiredFeatures: [ 'hit-test' ] 屏幕空间命中测试,配合 reticle 把物体放置到真实平面
examples/webxr_ar_plane_detection.html requiredFeatures: [ 'plane-detection' ] 结合 XRPlanes 对象直接获取设备检测到的平面
examples/webxr_ar_lighting.html optionalFeatures: [ 'light-estimation' ] 环境光照估计,让 3D 内容与现实光照匹配
examples/webxr_ar_camera_access.html requiredFeatures: [ 'camera-access' ] 通过 renderer.xr.getCameraTexture( view.camera ) 拿到相机画面作为贴图

以 hit-test 为例,示例中的按钮创建与渲染器初始化是标准四步:new THREE.WebGLRenderer( { antialias: true, alpha: true } )setAnimationLooprenderer.xr.enabled = trueARButton.createButton( renderer, { requiredFeatures: [ 'hit-test' ] } )examples/webxr_ar_hittest.html)。后续在 sessionstart 回调中通过 session.requestHitTestSource 获取命中源,在 select 事件中把 reticle 的世界矩阵分解后放置新物体。

与 XRButton 的关系及选型建议

three.js 同时提供 XRButton(文档见 docs/pages/XRButton.html.md),其方法签名与 ARButton.createButton 完全相同。从 XRButton 的文档描述看,它会优先尝试 immersive-ar,设备不支持时回退到 immersive-vr。因此选型逻辑可以归纳为:

  • 应用只服务于 AR(如手机上的增强现实放置类体验):用 ARButton,语义清晰,且 AR NOT SUPPORTED 的提示对用户更准确;
  • 应用希望同一套代码兼顾手机 AR 与头显 VR:用 XRButton,牺牲少量提示精度换取跨形态覆盖。

小结

ARButton 用一行 document.body.appendChild( ARButton.createButton( renderer ) ) 的背后,封装了完整的 WebXR immersive-ar 接入链路:安全上下文检查、能力探测、按钮状态机(START AR / STOP AR / 各类不可用提示)、dom-overlay 关闭入口自动注入、local 参考空间配置与 offerSession 系统级唤起。使用时只要记住三点:

  1. rendererxr.enabled = true、使用 setAnimationLoop,并建议开启 alpha: true
  2. 通过第二个参数 sessionInit 声明 requiredFeatures / optionalFeatures,并意识到 ARButton 可能向其中追加 dom-overlay 相关字段;
  3. 运行环境必须是 HTTPS(或 localhost),否则页面得到的将是 WEBXR NEEDS HTTPS 提示链接而非可点击按钮。

更多 API 细节可参考 examples/jsm/webxr/ARButton.js 源码与官方 API 页 docs/pages/ARButton.html

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
983
503
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384