1. Three.js 相机控制器:OrbitControls、FlyControls等

我来详细介绍一下 Three.js 中常用的相机控制器及其用法:

1.1. OrbitControls(轨道控制器)

最常用的控制器,适合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);
}

1.2. FlyControls(飞行控制器)

第一人称飞行模拟,类似飞行游戏。

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);  // 需要传入时间差
}

1.3. FirstPersonControls(第一人称控制器)

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());
}

1.4. PointerLockControls(指针锁定控制器)

完全鼠标控制,适合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;
    }
});

1.5. TrackballControls(轨迹球控制器)

无限制的轨道控制器,可以无限旋转。

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;// 动态阻尼系数

1.6. TransformControls(变换控制器)

用于对象变换(移动、旋转、缩放)。

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'

1.7. 自定义控制器示例

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;
    }
}

1.8. 控制器选择建议

控制器选择建议.png

1.9. 安装和导入

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>

1.10. 常见问题解决

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 提供了丰富的交互方式,可以根据具体需求选择合适的控制器或组合使用多个控制器。