关于 threejs-syntax-controls
面向 Three.js 开发者的相机与对象控制参考技能,介绍各类控制器的选择和用法。涵盖初始化、更新、清理及交互集成注意事项。
主要功能
- 01按交互方式选择控制器
- 02轨道、地图与飞行相机控制
- 03第一人称与指针锁定控制
- 04对象变换与拖拽操纵器
- 05生命周期和控制器集成指导
适用场景
- 01为模型查看器添加环绕与缩放
- 02构建第一人称相机交互
- 03通过操纵器编辑对象变换
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ impertio-studio/ three.js-claude-skill-package --skill threejs-syntax-controls安装后在 Claude Code 中输入/threejs-syntax-controls确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
.gitkeepreferences/anti-patterns.mdexamples.mdmethods.md详细介绍
threejs-syntax-controls
快速参考
控件选择决策树
| 使用场景 | 控件 | 原因 |
|---|---|---|
| 从各个角度查看 3D 模型 | OrbitControls | 围绕目标点旋转、平移和缩放 |
| 俯视地图或 2D 风格的导航 | MapControls | 左键拖动可平移,右键拖动可旋转 |
| 自由飞行编辑器或太空场景 | FlyControls | 六自由度,WASD + 鼠标 |
| 使用指针锁定的第一人称游戏 | PointerLockControls | 隐藏光标并捕获鼠标移动 |
| 不使用指针锁定的第一人称视角 | FirstPersonControls | 无需浏览器锁定 API 的鼠标视角控制 |
| 通过操纵器移动、旋转和缩放对象 | TransformControls | 交互式平移、旋转和缩放控制柄 |
| 沿平面拖动对象 | DragControls | 点击并拖动对象以重新定位 |
| 不受约束的旋转(无万向节锁) | ArcballControls | 带动画的完整球面旋转 |
| 不受约束的旋转(更简单) | TrackballControls | 类似 OrbitControls,但没有极点约束 |
导入路径(Three.js r160+)
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { MapControls } from 'three/addons/controls/MapControls.js';
import { FlyControls } from 'three/addons/controls/FlyControls.js';
import { FirstPersonControls } from 'three/addons/controls/FirstPersonControls.js';
import { PointerLockControls } from 'three/addons/controls/PointerLockControls.js';
import { TransformControls } from 'three/addons/controls/TransformControls.js';
import { TrackballControls } from 'three/addons/controls/TrackballControls.js';
import { ArcballControls } from 'three/addons/controls/ArcballControls.js';
import { DragControls } from 'three/addons/controls/DragControls.js';
始终对 r160+ 使用 'three/addons/controls/...'。旧路径 'three/examples/jsm/controls/...' 仍可用,但已弃用。
重要警告
当 enableDamping 或 autoRotate 为 true 时,始终在动画循环中调用 controls.update()。否则用户交互结束后摄像机将冻结。
移除控件时,始终调用 controls.dispose()。否则会泄漏 DOM 事件监听器(pointermove、wheel、keydown),导致内存泄漏和残留交互。
切勿在同一摄像机上同时附加两个摄像机控制类,除非禁用了其中一个。在同一摄像机上同时使用 OrbitControls 和 FlyControls 会导致移动异常。
TransformControls 拖动时,始终禁用 OrbitControls。监听 dragging-changed 事件并切换 orbitControls.enabled。
始终从用户手势(点击处理程序)中调用 PointerLockControls.lock()。如果没有用户交互,浏览器会拒绝指针锁定请求。
始终向 FlyControls.update(delta) 传递 delta 时间。未传递参数或传递经过的时间都会导致速度受帧率影响。
控件生命周期
每个控件都遵循相同的生命周期模式:
construct --> configure --> attach to loop --> dispose on cleanup
步骤 1:构造
const controls = new OrbitControls(camera, renderer.domElement);
第二个参数始终传入 renderer.domElement。传入 document 或 document.body 会导致控件全局捕获事件,从而破坏 UI 覆盖层。
步骤 2:配置
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.minDistance = 2;
controls.maxDistance = 50;
controls.target.set(0, 1, 0);
步骤 3:在渲染循环中更新
function animate() {
requestAnimationFrame(animate);
controls.update(); // REQUIRED when enableDamping or autoRotate is true
renderer.render(scene, camera);
}
animate();
步骤 4:清理时释放
controls.dispose();
OrbitControls
最常用的控件。围绕目标点旋转、平移和缩放。
构造函数
new OrbitControls(camera: THREE.Camera, domElement: HTMLElement)
主要属性
| 属性 | 类型 | 默认值 | 描述 |
|---|---|---|---|
enabled | boolean | true | 启用/禁用所有交互 |
target | Vector3 | (0,0,0) | 环绕焦点 |
enableDamping | boolean | false | 启用平滑惯性移动 |
dampingFactor | number | 0.05 | 惯性强度(0-1) |
autoRotate | boolean | false | 自动围绕目标旋转 |
autoRotateSpeed | number | 2.0 | 60fps 下的度/秒 |
enablePan | boolean | true | 允许平移 |
enableRotate | boolean | true | 允许旋转 |
enableZoom | boolean | true | 允许缩放 |
minDistance | number | 0 | 最小缩放距离(PerspectiveCamera) |
maxDistance | number | Infinity | 最大缩放距离(PerspectiveCamera) |
minZoom | number | 0 | 最小缩放值(OrthographicCamera) |
maxZoom | number | Infinity | 最大缩放值(OrthographicCamera) |
minPolarAngle | number | 0 | 最小垂直角度(弧度) |
maxPolarAngle | number | Math.PI | 最大垂直角度(弧度) |
minAzimuthAngle | number | -Infinity | 最小水平角度(弧度) |
maxAzimuthAngle | number | Infinity | 最大水平角度(弧度) |
screenSpacePanning | boolean | true | 在屏幕平面(true)或水平面(false)内平移 |
zoomToCursor | boolean | false | 朝光标位置缩放 |
panSpeed | number | 1.0 | 平移速度倍率 |
rotateSpeed | number | 1.0 | 旋转速度倍率 |
zoomSpeed | number | 1.0 | 缩放速度倍率 |
mouseButtons | object | {LEFT: ROTATE, MIDDLE: DOLLY, RIGHT: PAN} | 鼠标按键映射 |
touches | object | {ONE: ROTATE, TWO: DOLLY_PAN} | 触摸手势映射 |
keys | object | {LEFT, UP, RIGHT, BOTTOM} | 用于平移的箭头键代码 |
方法
| 方法 | 签名 | 描述 |
|---|---|---|
update(deltaTime?) | (number?) => boolean | 更新控制状态。启用阻尼/自动旋转时,必须每帧调用 |
dispose() | () => void | 移除所有事件监听器 |
saveState() | () => void | 保存当前相机位置/目标/缩放值 |
reset() | () => void | 恢复到上次保存的状态 |
getDistance() | () => number | 相机到目标的距离 |
getPolarAngle() | () => number | 垂直角度(弧度) |
getAzimuthalAngle() | () => number | 水平角度(弧度) |
listenToKeyEvents(el) | (HTMLElement) => void | 启用键盘平移 |
stopListenToKeyEvents() | () => void | 禁用键盘平移 |
事件
| 事件 | 触发条件 |
|---|---|
change | 相机位置或目标发生变化 |
start | 用户开始交互(pointerdown) |
end | 用户结束交互(pointerup) |
MapControls
针对俯视地图导航优化的 OrbitControls 子类。
| 按键 | OrbitControls | MapControls |
|---|---|---|
| 鼠标左键 | 旋转 | 平移 |
| 鼠标中键 | Dolly | Dolly |
| 鼠标右键 | 平移 | 旋转 |
所有属性、方法和事件都与 OrbitControls 相同。唯一的区别是默认的 mouseButtons 映射,以及 screenSpacePanning 默认值为 true。
FlyControls
六自由度飞行相机。使用 WASD 移动、QE 翻滚、RF 上下移动。
主要属性
| 属性 | 类型 | 默认值 | 描述 |
|---|---|---|---|
movementSpeed | number | 1.0 | 平移速度 |
rollSpeed | number | 0.005 | 翻滚旋转速度 |
dragToLook | boolean | false | 需要拖动鼠标才能旋转(而非始终跟随鼠标) |
autoForward | boolean | false | 自动向前移动 |
方法
update(delta)-- 始终传入时钟的delta时间。绝不能省略此参数。dispose()-- 移除事件监听器。
PointerLockControls
使用 Pointer Lock API 的第一人称摄像机。隐藏并捕获鼠标光标。
关键属性
| 属性 | 类型 | 默认值 | 描述 |
|---|---|---|---|
isLocked | boolean | 只读 | 指针当前是否已锁定 |
maxPolarAngle | number | Math.PI | 最大垂直视角 |
minPolarAngle | number | 0 | 最小垂直视角 |
pointerSpeed | number | 1.0 | 鼠标灵敏度倍率 |
方法
| 方法 | 描述 |
|---|---|
lock() | 请求锁定指针(必须由用户手势触发) |
unlock() | 退出指针锁定 |
connect() | 添加事件监听器 |
disconnect() | 移除事件监听器 |
dispose() | 完整清理(调用 disconnect) |
getObject() | 返回受控摄像机 |
getDirection(target) | 将视线方向写入目标 Vector3 |
moveForward(distance) | 向前移动摄像机 |
moveRight(distance) | 横向移动摄像机 |
事件
| 事件 | 触发条件 |
|---|---|
change | 摄像机朝向发生变化 |
lock | 指针锁定已生效 |
unlock | 指针锁定已解除 |
务必在动画循环中自行实现 WASD 移动。PointerLockControls 只处理视线方向,不处理位置。
TransformControls
用于移动、旋转和缩放场景对象的交互式操作控件。
关键属性
| 属性 | 类型 | 默认值 | 描述 |
|---|---|---|---|
mode | string | 'translate' | 'translate'、'rotate' 或 'scale' |
space | string | 'world' | 'world' 或 'local' 坐标空间 |
showX | boolean | true | 显示 X 轴控柄 |
showY | boolean | true | 显示 Y 轴控柄 |
showZ | boolean | true | 显示 Z 轴控柄 |
size | number | 1 | 操作控件的视觉缩放比例 |
translationSnap | `number | null` | null |
rotationSnap | `number | null` | null |
scaleSnap | `number | null` | null |
dragging | boolean | 只读 | 用户当前是否正在拖动 |
方法
| 方法 | 描述 |
|---|---|
attach(object) | 将操作控件附加到场景对象 |
detach() | 从当前对象移除操作控件 |
setMode(mode) | 设置变换模式 |
setSpace(space) | 设置坐标空间 |
setSize(size) | 设置操作控件缩放比例 |
setTranslationSnap(snap) | 设置位置吸附 |
setRotationSnap(snap) | 设置旋转吸附 |
setScaleSnap(snap) | 设置缩放吸附 |
getRaycaster() | 访问内部射线投射器 |
dispose() | 清理 |
事件
| 事件 | 触发条件 |
|---|---|
change | 操作控件外观发生变化 |
dragging-changed | 开始拖动时,event.value 为 true;结束时为 false |
objectChange | 附加对象的变换已修改 |
mouseDown | 指针在操作控件上按下 |
mouseUp | 指针从操作控件上释放 |
关键集成模式
务必在操作控件拖动期间禁用摄像机控件:
transformControls.addEventListener('dragging-changed', (event) => {
orbitControls.enabled = !event.value;
});
务必将 TransformControls 添加到场景中:scene.add(transformControls.getHelper()) 或 scene.add(transformControls)。
简要概述:其他控件
ArcballControls
支持动画状态的无限制旋转。没有极角限制——摄像机可以向所有方向自由旋转。最适合 CAD 风格的模型检查。
TrackballControls
类似于没有极角限制的 OrbitControls。摄像机可以越过极点旋转。属性:rotateSpeed、zoomSpeed、panSpeed、staticMoving、dynamicDampingFactor。
DragControls
沿平面拖动场景对象。构造函数:new DragControls(objects, camera, domElement)。事件:dragstart、drag、dragend、hoveron、hoveroff。
FirstPersonControls
不使用指针锁定的鼠标视角摄像机。属性:movementSpeed、lookSpeed、activeLook、constrainVertical、verticalMin、verticalMax。
参考链接
- references/methods.md -- 所有控件的完整 API 签名
- references/examples.md -- 各类控件的可运行代码示例
- references/anti-patterns.md -- 错误做法
官方来源
- https://threejs.org/docs/#examples/en/controls/OrbitControls
- https://threejs.org/docs/#examples/en/controls/MapControls
- https://threejs.org/docs/#examples/en/controls/FlyControls
- https://threejs.org/docs/#examples/en/controls/PointerLockControls
- https://threejs.org/docs/#examples/en/controls/TransformControls