260 lines
5.8 KiB
Markdown
260 lines
5.8 KiB
Markdown
# Camera Controls (Addons)
|
|
|
|
Interactive camera navigation systems.
|
|
|
|
## OrbitControls (Most Common)
|
|
|
|
Orbit camera around a target:
|
|
|
|
```javascript
|
|
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
|
|
|
const controls = new OrbitControls(camera, renderer.domElement);
|
|
|
|
// Target point
|
|
controls.target.set(0, 0, 0);
|
|
|
|
// Damping (smooth motion)
|
|
controls.enableDamping = true;
|
|
controls.dampingFactor = 0.05;
|
|
|
|
// Zoom limits
|
|
controls.minDistance = 5;
|
|
controls.maxDistance = 50;
|
|
|
|
// Rotation limits
|
|
controls.minPolarAngle = 0; // radians
|
|
controls.maxPolarAngle = Math.PI / 2; // prevent going below ground
|
|
controls.minAzimuthAngle = -Math.PI / 4; // horizontal limit
|
|
controls.maxAzimuthAngle = Math.PI / 4;
|
|
|
|
// Behavior
|
|
controls.enablePan = true;
|
|
controls.enableZoom = true;
|
|
controls.enableRotate = true;
|
|
controls.autoRotate = true;
|
|
controls.autoRotateSpeed = 2.0;
|
|
|
|
// Mouse buttons
|
|
controls.mouseButtons = {
|
|
LEFT: THREE.MOUSE.ROTATE,
|
|
MIDDLE: THREE.MOUSE.DOLLY,
|
|
RIGHT: THREE.MOUSE.PAN
|
|
};
|
|
|
|
// In animation loop (required if damping enabled)
|
|
function animate() {
|
|
controls.update();
|
|
renderer.render(scene, camera);
|
|
requestAnimationFrame(animate);
|
|
}
|
|
|
|
// Events
|
|
controls.addEventListener('change', () => {
|
|
renderer.render(scene, camera);
|
|
});
|
|
```
|
|
|
|
## MapControls
|
|
|
|
Bird's-eye map navigation (like OrbitControls but different mouse behavior):
|
|
|
|
```javascript
|
|
import { MapControls } from 'three/addons/controls/MapControls.js';
|
|
|
|
const controls = new MapControls(camera, renderer.domElement);
|
|
controls.enableDamping = true;
|
|
controls.screenSpacePanning = false;
|
|
controls.maxPolarAngle = Math.PI / 2;
|
|
|
|
// Mouse buttons
|
|
controls.mouseButtons = {
|
|
LEFT: THREE.MOUSE.PAN,
|
|
MIDDLE: THREE.MOUSE.DOLLY,
|
|
RIGHT: THREE.MOUSE.ROTATE
|
|
};
|
|
```
|
|
|
|
## FirstPersonControls
|
|
|
|
FPS-style camera movement:
|
|
|
|
```javascript
|
|
import { FirstPersonControls } from 'three/addons/controls/FirstPersonControls.js';
|
|
|
|
const controls = new FirstPersonControls(camera, renderer.domElement);
|
|
|
|
controls.movementSpeed = 10;
|
|
controls.lookSpeed = 0.1;
|
|
controls.lookVertical = true;
|
|
controls.constrainVertical = true;
|
|
controls.verticalMin = 1.0;
|
|
controls.verticalMax = 2.0;
|
|
|
|
// Requires delta time
|
|
const clock = new THREE.Clock();
|
|
function animate() {
|
|
const delta = clock.getDelta();
|
|
controls.update(delta);
|
|
renderer.render(scene, camera);
|
|
requestAnimationFrame(animate);
|
|
}
|
|
```
|
|
|
|
## FlyControls
|
|
|
|
Free-form flying navigation:
|
|
|
|
```javascript
|
|
import { FlyControls } from 'three/addons/controls/FlyControls.js';
|
|
|
|
const controls = new FlyControls(camera, renderer.domElement);
|
|
|
|
controls.movementSpeed = 10;
|
|
controls.rollSpeed = Math.PI / 24;
|
|
controls.autoForward = false;
|
|
controls.dragToLook = false;
|
|
|
|
const clock = new THREE.Clock();
|
|
function animate() {
|
|
const delta = clock.getDelta();
|
|
controls.update(delta);
|
|
renderer.render(scene, camera);
|
|
requestAnimationFrame(animate);
|
|
}
|
|
```
|
|
|
|
## PointerLockControls
|
|
|
|
Locked pointer FPS controls:
|
|
|
|
```javascript
|
|
import { PointerLockControls } from 'three/addons/controls/PointerLockControls.js';
|
|
|
|
const controls = new PointerLockControls(camera, renderer.domElement);
|
|
|
|
// Lock pointer on click
|
|
renderer.domElement.addEventListener('click', () => {
|
|
controls.lock();
|
|
});
|
|
|
|
controls.addEventListener('lock', () => {
|
|
console.log('Locked');
|
|
});
|
|
|
|
controls.addEventListener('unlock', () => {
|
|
console.log('Unlocked');
|
|
});
|
|
|
|
// Movement
|
|
const velocity = new THREE.Vector3();
|
|
const direction = new THREE.Vector3();
|
|
|
|
window.addEventListener('keydown', (event) => {
|
|
switch (event.code) {
|
|
case 'KeyW': moveForward = true; break;
|
|
case 'KeyS': moveBackward = true; break;
|
|
case 'KeyA': moveLeft = true; break;
|
|
case 'KeyD': moveRight = true; break;
|
|
}
|
|
});
|
|
|
|
function animate() {
|
|
if (controls.isLocked) {
|
|
// Calculate movement
|
|
direction.z = Number(moveForward) - Number(moveBackward);
|
|
direction.x = Number(moveRight) - Number(moveLeft);
|
|
direction.normalize();
|
|
|
|
controls.moveForward(direction.z * 10);
|
|
controls.moveRight(direction.x * 10);
|
|
}
|
|
renderer.render(scene, camera);
|
|
requestAnimationFrame(animate);
|
|
}
|
|
```
|
|
|
|
## TrackballControls
|
|
|
|
Intuitive rotation (no gimbal lock):
|
|
|
|
```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.staticMoving = true;
|
|
controls.dynamicDampingFactor = 0.3;
|
|
|
|
function animate() {
|
|
controls.update();
|
|
renderer.render(scene, camera);
|
|
requestAnimationFrame(animate);
|
|
}
|
|
```
|
|
|
|
## ArcballControls
|
|
|
|
3D rotation with virtual ball metaphor:
|
|
|
|
```javascript
|
|
import { ArcballControls } from 'three/addons/controls/ArcballControls.js';
|
|
|
|
const controls = new ArcballControls(camera, renderer.domElement, scene);
|
|
|
|
controls.enablePan = true;
|
|
controls.enableZoom = true;
|
|
controls.enableRotate = true;
|
|
controls.cursorZoom = true;
|
|
|
|
function animate() {
|
|
controls.update();
|
|
renderer.render(scene, camera);
|
|
requestAnimationFrame(animate);
|
|
}
|
|
```
|
|
|
|
## Controls Comparison
|
|
|
|
**OrbitControls**: Product viewers, 3D models, general use
|
|
**MapControls**: Top-down maps, strategy games
|
|
**FirstPersonControls**: Architectural walkthroughs
|
|
**FlyControls**: Space navigation, creative tools
|
|
**PointerLockControls**: FPS games
|
|
**TrackballControls**: CAD applications
|
|
**ArcballControls**: Scientific visualization
|
|
|
|
## Common Patterns
|
|
|
|
```javascript
|
|
// Disable controls during UI interaction
|
|
transformControls.addEventListener('dragging-changed', (event) => {
|
|
orbitControls.enabled = !event.value;
|
|
});
|
|
|
|
// Reset camera position
|
|
function resetCamera() {
|
|
controls.reset();
|
|
}
|
|
|
|
// Animate camera to position
|
|
function moveCameraTo(position, target) {
|
|
gsap.to(camera.position, {
|
|
duration: 1,
|
|
x: position.x,
|
|
y: position.y,
|
|
z: position.z,
|
|
onUpdate: () => controls.update()
|
|
});
|
|
gsap.to(controls.target, {
|
|
duration: 1,
|
|
x: target.x,
|
|
y: target.y,
|
|
z: target.z
|
|
});
|
|
}
|
|
```
|