В Three.js создание динамических сцен невозможно без
корректной организации цикла анимации. Основной инструмент для этого —
метод render вместе с браузерным API
requestAnimationFrame. Их правильное
сочетание обеспечивает плавную отрисовку и оптимальное использование
ресурсов процессора и GPU.
Метод requestAnimationFrame является стандартным
способом реализации анимации в браузере. Его особенности:
setInterval или setTimeout.timestamp, представляющий текущий
момент времени в миллисекундах с начала загрузки документа. Он удобен
для расчета изменения состояния объектов относительно времени.Пример базового использования:
function animate(timestamp) {
// Логика анимации объектов
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera); // Отрисовка сцены
requestAnimationFrame(animate); // Рекурсивный вызов для следующего кадра
}
requestAnimationFrame(animate);
Ключевой момент — рекурсивный вызов
requestAnimationFrame внутри самой функции
анимации. Это обеспечивает непрерывный цикл.
Метод renderer.render(scene, camera) отвечает за
фактическую отрисовку сцены на холсте (canvas). Основные
аспекты его применения:
Пример использования без цикла:
renderer.render(scene, camera); // Один кадр, без анимации
В сочетании с requestAnimationFrame метод
render становится частью непрерывного цикла:
function animate() {
updateObjects(); // Обновление состояний объектов
renderer.render(scene, camera); // Отрисовка
requestAnimationFrame(animate); // Следующий кадр
}
animate();
При построении сложных сцен важно разделять логическую часть обновления сцены и отрисовку. Рекомендуется структура:
renderer.render.requestAnimationFrame.Пример с контроллером камеры:
function animate() {
controls.update(); // Обновление орбитальных контроллеров
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
animate();
let lastTime = 0;
function animate(timestamp) {
if (timestamp - lastTime >= 1000 / 30) { // 30 FPS
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
lastTime = timestamp;
}
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
let previousTime = performance.now();
function animate(currentTime) {
const delta = (currentTime - previousTime) / 1000; // секунды
cube.rotation.x += delta * Math.PI; // скорость вращения рад/сек
cube.rotation.y += delta * Math.PI;
renderer.render(scene, camera);
previousTime = currentTime;
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
Three.js часто используется совместно с библиотеками анимации,
например GSAP. В этом случае
requestAnimationFrame может быть управляем библиотекой, а
renderer.render вызывается в ее callback для синхронизации
с временной шкалой:
gsap.ticker.add(() => {
renderer.render(scene, camera);
});
Такой подход позволяет легко комбинировать временные анимации объектов с пользовательским циклом рендеринга.
autoClear — по умолчанию
каждый кадр очищает холст. Для наложения нескольких сцен можно выключить
renderer.autoClear = false.setAnimationLoop — метод
Three.js, альтернативный requestAnimationFrame, особенно
полезный для WebXR:renderer.setAnimationLoop(() => {
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
});
Он автоматически синхронизируется с VR/AR сеансами, что делает код более универсальным.
requestAnimationFrame гарантирует плавную анимацию, но
не фиксированную частоту кадров.renderer.render — чисто функциональная операция,
вызываемая столько раз, сколько нужно для визуализации.Этот цикл анимации является фундаментом для любых интерактивных 3D-приложений на Three.js, от простых вращающихся объектов до сложных VR-сцен с физикой и пользовательскими контроллерами.