我来详细介绍一下 Three.js 中常用的相机控制器及其用法:
最常用的控制器,适合3D场景查看。
javascript
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// 基本使用
const controls = new OrbitControls(camera, renderer.domElement);
// 配置选项
controls.enableDamping = true; // 启用阻尼(惯性效果)
controls.dampingFactor = 0.05; // 阻尼系数
controls.rotateSpeed = 0.5; // 旋转速度
controls.zoomSpeed = 1.0; // 缩放速度
controls.panSpeed = 0.8; // 平移速度
// 限制
controls.minDistance = 1; // 最小缩放距离
controls.maxDistance = 1000; // 最大缩放距离
controls.maxPolarAngle = Math.PI; // 最大仰角(防止翻转)
// 禁用特定操作
controls.enableRotate = true; // 启用旋转
controls.enableZoom = true; // 启用缩放
controls.enablePan = true; // 启用平移
// 在动画循环中更新
function animate() {
controls.update();
renderer.render(scene, camera);
}
第一人称飞行模拟,类似飞行游戏。
javascript
import { FlyControls } from 'three/addons/controls/FlyControls.js';
const controls = new FlyControls(camera, renderer.domElement);
// 配置
controls.movementSpeed = 100; // 移动速度
controls.rollSpeed = Math.PI / 24; // 滚转速度
controls.dragToLook = true; // 拖拽查看(false时为鼠标直接控制)
controls.autoForward = false; // 是否自动前进
// 更新(需要高频率)
function animate() {
const delta = clock.getDelta();
controls.update(delta); // 需要传入时间差
}
FPS游戏风格的控制器。
javascript
import { FirstPersonControls } from 'three/addons/controls/FirstPersonControls.js';
const controls = new FirstPersonControls(camera, renderer.domElement);
controls.lookSpeed = 0.1; // 视角移动速度
controls.movementSpeed = 10; // 移动速度
controls.lookVertical = true; // 允许垂直视角
controls.constrainVertical = true; // 限制垂直视角角度
controls.verticalMin = 1.0; // 最小垂直角度
controls.verticalMax = 2.0; // 最大垂直角度
// 更新
function animate() {
controls.update(clock.getDelta());
}
完全鼠标控制,适合FPS游戏。
javascript
import { PointerLockControls } from 'three/addons/controls/PointerLockControls.js';
const controls = new PointerLockControls(camera, renderer.domElement);
// 需要用户交互来激活
document.getElementById('startButton').addEventListener('click', () => {
controls.lock(); // 锁定指针
});
// 监听锁定状态变化
controls.addEventListener('lock', () => {
console.log('锁定');
});
controls.addEventListener('unlock', () => {
console.log('解锁');
});
// 移动控制(需要自己实现)
const moveForward = false, moveLeft = false, moveBackward = false, moveRight = false;
document.addEventListener('keydown', (event) => {
switch(event.code) {
case 'KeyW': moveForward = true; break;
case 'KeyA': moveLeft = true; break;
case 'KeyS': moveBackward = true; break;
case 'KeyD': moveRight = true; break;
}
});
无限制的轨道控制器,可以无限旋转。
javascript
import { TrackballControls } from 'three/addons/controls/TrackballControls.js';
const controls = new TrackballControls(camera, renderer.domElement);
controls.rotateSpeed = 1.0; // 旋转速度
controls.zoomSpeed = 1.2; // 缩放速度
controls.panSpeed = 0.8; // 平移速度
controls.noZoom = false; // 禁用缩放
controls.noPan = false; // 禁用平移
controls.staticMoving = false; // 静态移动
controls.dynamicDampingFactor = 0.2;// 动态阻尼系数
用于对象变换(移动、旋转、缩放)。
javascript
import { TransformControls } from 'three/addons/controls/TransformControls.js';
const controls = new TransformControls(camera, renderer.domElement);
// 添加到场景
scene.add(controls);
// 附加到要控制的对象
controls.attach(object);
// 监听变换事件
controls.addEventListener('dragging-changed', (event) => {
orbitControls.enabled = !event.value;
});
// 设置变换模式
controls.setMode('translate'); // 'translate' | 'rotate' | 'scale'
controls.setSpace('world'); // 'world' | 'local'
javascript
class SimpleOrbitControls {
constructor(camera, domElement) {
this.camera = camera;
this.domElement = domElement;
this.rotateSpeed = 0.5;
this.zoomSpeed = 0.1;
this.panSpeed = 0.3;
this.isMouseDown = false;
this.previousMouse = { x: 0, y: 0 };
this.init();
}
init() {
this.domElement.addEventListener('mousedown', this.onMouseDown.bind(this));
this.domElement.addEventListener('mousemove', this.onMouseMove.bind(this));
this.domElement.addEventListener('mouseup', this.onMouseUp.bind(this));
this.domElement.addEventListener('wheel', this.onMouseWheel.bind(this));
}
onMouseDown(event) {
this.isMouseDown = true;
this.previousMouse.x = event.clientX;
this.previousMouse.y = event.clientY;
}
onMouseMove(event) {
if (!this.isMouseDown) return;
const deltaX = event.clientX - this.previousMouse.x;
const deltaY = event.clientY - this.previousMouse.y;
// 旋转逻辑
this.camera.rotation.y += deltaX * this.rotateSpeed * 0.01;
this.camera.rotation.x += deltaY * this.rotateSpeed * 0.01;
this.previousMouse.x = event.clientX;
this.previousMouse.y = event.clientY;
}
onMouseWheel(event) {
// 缩放逻辑
this.camera.position.z += event.deltaY * this.zoomSpeed * 0.01;
}
onMouseUp() {
this.isMouseDown = false;
}
}

bash
# 通过npm安装
npm install three
# 或者使用CDN
<script src="https://cdn.jsdelivr.net/npm/three@0.162.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.162.0/examples/js/controls/OrbitControls.js"></script>
javascript
// 1. 控制器不工作
// 确保在动画循环中调用 controls.update()
// 2. 旋转方向相反
controls.mouseButtons = {
LEFT: THREE.MOUSE.ROTATE,
MIDDLE: THREE.MOUSE.DOLLY,
RIGHT: THREE.MOUSE.PAN
};
// 3. 与其他事件冲突
// 禁用页面滚动
renderer.domElement.addEventListener('wheel', (e) => {
e.preventDefault();
}, { passive: false });
// 4. 响应窗口大小变化
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
这些控制器为 Three.js 提供了丰富的交互方式,可以根据具体需求选择合适的控制器或组合使用多个控制器。