В библиотеке Three.js камера является ключевым элементом сцены, определяющим, как объекты визуализируются на экране. Для создания реалистичных и динамичных анимаций часто требуется плавное перемещение камеры между точками, вращение вокруг объектов или смена перспективы. Такие эффекты обеспечивают глубину сцены и вовлечение пользователя, особенно в интерактивных визуализациях и играх.
Плавное перемещение камеры можно реализовать с помощью библиотек анимации, таких как GSAP или Tween.js, которые позволяют управлять значениями координат камеры и её целевых точек с высокой точностью и плавностью.
GSAP (GreenSock Animation Platform) предоставляет гибкий и
производительный инструмент для анимации свойств объектов в
JavaScript. В контексте Three.js это позволяет анимировать положение
камеры и её точку взгляда через объект controls (например,
OrbitControls).
Пример плавного перемещения камеры к новой позиции:
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { gsap } from 'gsap';
const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
camera.position.set(0, 2, 5);
const controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0, 0);
function moveCamera(targetPosition, targetLookAt, duration = 2) {
gsap.to(camera.position, {
x: targetPosition.x,
y: targetPosition.y,
z: targetPosition.z,
duration: duration,
ease: "power2.inOut",
onUpdate: () => controls.update()
});
gsap.to(controls.target, {
x: targetLookAt.x,
y: targetLookAt.y,
z: targetLookAt.z,
duration: duration,
ease: "power2.inOut",
onUpdate: () => controls.update()
});
}
// Пример использования
moveCamera(new THREE.Vector3(5, 3, 10), new THREE.Vector3(0, 1, 0), 3);
Ключевые моменты:
camera.position анимируется напрямую.controls.target обновляется параллельно, чтобы камера
плавно меняла направление взгляда.onUpdate используется для синхронизации
OrbitControls с текущим состоянием камеры.GSAP позволяет легко добавлять кривые ускорения (ease), создавая более естественные движения камеры.
Tween.js — это лёгкая библиотека для анимации значений с поддержкой интерполяций. Она хорошо подходит для проектов, где требуется меньше зависимостей, но нужна точная настройка времени и кривых.
Пример анимации камеры с Tween.js:
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import TWEEN from '@tweenjs/tween.js';
const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
camera.position.set(0, 2, 5);
const controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0, 0);
function moveCameraTween(targetPosition, targetLookAt, duration = 2000) {
const positionTween = new TWEEN.Tween(camera.position)
.to({ x: targetPosition.x, y: targetPosition.y, z: targetPosition.z }, duration)
.easing(TWEEN.Easing.Quadratic.InOut)
.onUpdate(() => controls.update());
const targetTween = new TWEEN.Tween(controls.target)
.to({ x: targetLookAt.x, y: targetLookAt.y, z: targetLookAt.z }, duration)
.easing(TWEEN.Easing.Quadratic.InOut)
.onUpdate(() => controls.update());
positionTween.start();
targetTween.start();
}
// В главном цикле рендеринга
function animate(time) {
requestAnimationFrame(animate);
TWEEN.update(time);
renderer.render(scene, camera);
}
animate();
Особенности Tween.js:
TWEEN.update() в
цикле рендеринга.Easing) для
создания естественных ускорений и замедлений.Для создания сложных анимаций полезно задавать маршрут камеры через массив ключевых точек. Это позволяет плавно перемещаться между несколькими локациями сцены.
Пример с GSAP:
const points = [
{ position: new THREE.Vector3(0, 2, 5), target: new THREE.Vector3(0, 0, 0) },
{ position: new THREE.Vector3(5, 3, 10), target: new THREE.Vector3(0, 1, 0) },
{ position: new THREE.Vector3(-3, 4, 7), target: new THREE.Vector3(1, 0, -1) }
];
let timeline = gsap.timeline();
points.forEach(point => {
timeline.to(camera.position, { x: point.position.x, y: point.position.y, z: point.position.z, duration: 2, ease: "power2.inOut", onUpdate: () => controls.update() });
timeline.to(controls.target, { x: point.target.x, y: point.target.y, z: point.target.z, duration: 2, ease: "power2.inOut", onUpdate: () => controls.update() }, "<");
});
"<" позволяет синхронизировать анимацию
controls.target с camera.position.timeline облегчает последовательное
выполнение нескольких анимаций и их повторное проигрывание.Использование requestAnimationFrame
Для плавного рендеринга все анимации должны работать в синхронизации с
основным циклом requestAnimationFrame.
Минимизация частых обновлений Излишнее
обновление controls.update() может снижать
производительность при большом количестве объектов.
Интерполяция кривых движения Применение кривых
easeInOut, power2 или cubic
делает перемещения камеры более естественными и визуально
приятными.
Синхронизация с событиями Плавные анимации камеры можно привязывать к пользовательским событиям, например, прокрутке страницы или кликам, что создаёт интерактивный опыт.
Помимо перемещения, часто требуется вращение камеры вокруг
точки. Это можно реализовать через изменение
controls.target или использование сферических
координат для вычисления позиции камеры.
Пример вращения вокруг объекта:
const radius = 5;
let angle = 0;
function rotateCamera() {
angle += 0.01;
camera.position.x = Math.cos(angle) * radius;
camera.position.z = Math.sin(angle) * radius;
camera.lookAt(new THREE.Vector3(0, 0, 0));
requestAnimationFrame(rotateCamera);
renderer.render(scene, camera);
}
rotateCamera();
camera.lookAt гарантирует, что камера всегда смотрит на
объект в центре.Для более сложных маршрутов движения можно использовать BezierCurve3 или CatmullRomCurve3, которые позволяют создавать кривые через несколько контрольных точек.
const curve = new THREE.CatmullRomCurve3([
new THREE.Vector3(0, 2, 5),
new THREE.Vector3(5, 3, 10),
new THREE.Vector3(-3, 4, 7),
new THREE.Vector3(0, 2, 5)
]);
let t = 0;
function animateCurve() {
t += 0.001;
if (t > 1) t = 0;
const point = curve.getPoint(t);
camera.position.copy(point);
camera.lookAt(new THREE.Vector3(0, 0, 0));
requestAnimationFrame(animateCurve);
renderer.render(scene, camera);
}
animateCurve();
getPoint(t) возвращает точку на кривой в зависимости от
параметра t (0–1).Эти техники создают основу для профессиональной анимации камеры в Three.js, объединяя гибкость GSAP и Tween.js с возможностями встроенных кривых и контроллеров сцены.