three.js ArcballControls 深度解析:虚拟弧面球导航、Gizmo 可视化与相机状态剪贴板管理
【免费下载链接】three.jsJavaScript 3D Library.
项目地址: https://gitcode.com/GitHub_Trending/th/three.js
ArcballControls是 three.js 官方 addons 中基于虚拟弧面球(arcball/trackball)的相机控制器,提供完整的触摸支持、双击聚焦(Focus)、FOV 调节、z 轴旋转以及通过剪贴板保存/恢复相机状态(Ctrl+C / Ctrl+V)等高级导航功能。本文基于官方 API 文档 ArcballControls 页面,结合其源码实现 ArcballControls.js 与官方示例 misc_controls_arcball.html,系统讲解它的构造参数、属性配置、鼠标动作映射机制、状态管理与事件体系,帮助你在复杂三维环境中构建专业级的交互式检查(inspection)界面。
![]()
核心机制:光标如何映射到虚拟弧面球
ArcballControls的基本思想是:将光标/手指的位置与移动映射到一个由 Gizmo 表示的虚拟弧面球表面上,并转译为直观、一致的相机运动。拖拽光标/手指会让相机以"保守"的方式绕弧面球中心旋转——光标回到起点时,相机也会回到起始朝向。除了平移(Pan)、缩放(Zoom)和双指捏合手势外,它还支持:
- 双击/双触聚焦(Focus):双击某个点时,控制器的兴趣点(target)会平滑移动到该点,相当于把关注对象拉到弧面球中心,便于在复杂环境中检查局部细节;
- FOV 调节:以"眩晕式"(vertigo-style)方式修改透视相机的视野角;
- z 轴旋转:绕视线方向旋转画面;
- 相机状态剪贴板:用
copyState()/pasteState()(快捷键 Ctrl+C / Ctrl+V)把当前相机状态以可读 JSON 文本形式拷贝到系统剪贴板并恢复。
与OrbitControls和TrackballControls不同,当动画开启时,ArcballControls不需要在渲染循环中手动调用update()——旋转阻尼与聚焦动画通过内部requestAnimationFrame自主驱动(源码中动画帧保存在_animationId,在dispose()时通过window.cancelAnimationFrame清理,见 ArcballControls.js)。
从源码结构看,整个控制器是一台有限状态机(FSA):STATE常量定义了IDLE、ROTATE、PAN、SCALE、FOV、FOCUS、ZROTATE、TOUCH_MULTI、ANIMATION_FOCUS、ANIMATION_ROTATE等状态(ArcballControls.js#L20-L33),INPUT常量则区分单指、双指、多指与光标输入。指针事件驱动状态切换,每次指针移动都会把光标"反投影"(unproject)到弧面球表面或切平面上,再换算出旋转轴与旋转角,这正是"回起点即回朝向"这一保守旋转行为的来源。
安装与导入
ArcballControls属于 addon,需要显式导入,而不是从核心包自动获得:
import { ArcballControls } from 'three/addons/controls/ArcballControls.js';
仓库中对应的源文件位于 examples/jsm/controls/ArcballControls.js,它继承自 addons 的通用Controls基类(继承链:EventDispatcher → Controls → ArcballControls),并额外挂载了GridHelper、EllipseCurve、Line等对象用于绘制 Gizmo。官方完整示例见 misc_controls_arcball.html,其中通过 importmap 将three/addons/映射到./jsm/目录:
<script type="importmap"> { "imports": { "three": "../build/three.module.js", "three/addons/": "./jsm/" } } </script>
构造函数
new ArcballControls( camera : Camera, domElement : HTMLElement, scene : Scene )
| 参数 | 说明 | 默认值 |
|---|
camera | 被控制的相机。相机不能是其他对象的子节点(场景本身除外) | 必填 |
domElement | 用于挂载事件监听器的 HTML 元素 | null |
scene | 相机所渲染的场景;不提供时无法显示 Gizmo | null |
从构造函数源码看,有几个值得注意的初始化行为(ArcballControls.js#L121-L454):
- 控制器构造时会调用
this.setCamera( camera ),立即把当前相机的位置、FOV、zoom、near/far 等记录为"初始状态"——这正是reset()与adjustNearFar工作的基准; - 如果传入了
scene,内部 Gizmo 容器(一个Group)会被加入场景; initializeMouseActions()会注册默认的鼠标动作映射(详见下文);- 若
domElement非空,调用connect( domElement )绑定contextmenu、wheel、pointerdown、pointercancel等监听器,并设置touchAction = 'none'禁用页面触摸滚动——这意味着在移动设备上使用时,承载画布的区域将不再响应原生滚动手势。
官方示例的最小用法:
controls = new ArcballControls( camera, renderer.domElement, scene ); controls.addEventListener( 'change', render ); // 相机被控制器改变时触发重绘
属性完整参考
以下属性说明完整继承自 API 文档,并与源码中的默认值逐一核对。
.adjustNearFar : boolean
设为true时,每次执行缩放都会同步调整相机的 near 和 far 值,试图保持与初始 near/far 相同的可见范围;仅对透视相机生效。该功能要求相机初始状态(位置、near、far)在创建控制器前已正确配置,否则必须显式调用setCamera()重新记录初始状态。默认false。
.cursorZoom : boolean
设为true时,缩放以光标位置为中心(而非画面中心)。默认false。
.dampingFactor : number
当enableAnimations为true时使用的旋转阻尼惯性。默认25。
.enableAnimations : boolean
设为true时为旋转(阻尼甩动)和聚焦操作启用动画。默认true。
.enableFocus : boolean
启用/禁用双击(或双触)聚焦操作。默认true。
.enableGizmos : boolean
启用/禁用弧面球 Gizmo。默认true。
.enableGrid : boolean
设为true时,执行平移(Pan)操作期间会临时显示一个网格(仅桌面交互有效)。默认false。
.enablePan : boolean
启用/禁用相机平移。默认true。
.enableRotate : boolean
启用/禁用相机旋转。默认true。
.enableZoom : boolean
启用/禁用相机缩放。默认true。
.focusAnimationTime : number
聚焦动画的持续时间(毫秒)。默认500。
.maxDistance / .minDistance : number
透视相机允许的最大/最小 Dolly(推拉)距离。默认分别为Infinity和0。
.maxFov / .minFov : number
透视相机 FOV 的最大/最小值(度)。默认分别为90和5。
.maxZoom / .minZoom : number
正交相机允许的最大/最小 zoom 值。默认分别为Infinity和0。
.mouseActions : Array.