Анимация и delta time
Главный секрет честной анимации: привязывать движение к времени, а не к кадрам. Иначе на разных мониторах скорость поедет.
Delta time — это время (в секундах) с предыдущего кадра. Умножая скорость на delta, мы получаем движение, одинаковое при любом FPS.
Проблема фиксированного шага
В первом разделе мы писали cube.rotation.y += 0.01 каждый кадр. Это работает, пока у всех 60 кадров в секунду. Но на мониторе 144 Гц кадров в 2.4 раза больше — и куб закрутится в 2.4 раза быстрее. А если браузер просел до 30 FPS, всё замедлится. Анимация, привязанная к кадрам, ведёт себя по-разному на разном железе.
Решение: умножать на delta
Вместо «прибавить столько-то за кадр» говорим «двигаться со скоростью столько-то в секунду» и умножаем на длительность кадра. Покажем математику вживую: сравним поворот за секунду при 60 и 144 FPS со старым и новым подходом.
// Старый способ: фиксированный шаг за кадр
const stepPerFrame = 0.01;
console.log('Фикс. шаг за секунду при 60 FPS:', (stepPerFrame * 60).toFixed(2));
console.log('Фикс. шаг за секунду при 144 FPS:', (stepPerFrame * 144).toFixed(2));
// Новый способ: скорость * delta
const speed = 0.6; // радиан в секунду — целевая скорость
function rotatePerSecond(fps) {
const delta = 1 / fps; // длительность кадра
return speed * delta * fps; // суммарно за секунду
}
console.log('Через delta при 60 FPS:', rotatePerSecond(60).toFixed(2));
console.log('Через delta при 144 FPS:', rotatePerSecond(144).toFixed(2));
Вывод:
Фикс. шаг за секунду при 60 FPS: 0.60 Фикс. шаг за секунду при 144 FPS: 1.44 Через delta при 60 FPS: 0.60 Через delta при 144 FPS: 0.60
Старый способ даёт разную скорость (0.60 против 1.44!), а подход через delta — одинаковые 0.60 на любом мониторе. Это и есть цель.
THREE.Clock в реальном коде
В Three.js delta удобно брать из THREE.Clock: метод getDelta() возвращает секунды с прошлого вызова.
const clock = new THREE.Clock();
function animate() {
requestAnimationFrame(animate);
const delta = clock.getDelta(); // секунды с прошлого кадра
cube.rotation.y += 0.6 * delta; // 0.6 рад/сек на любом FPS
renderer.render(scene, camera);
}
animate();
Правило
Любое движение, поворот, изменение со временем умножайте на delta. Думайте в единицах «в секунду», а не «за кадр». Это единственный способ, чтобы игра или анимация ощущались одинаково у всех пользователей.
Итог
- delta — время с прошлого кадра; основа анимации, независимой от FPS.
- Фиксированный шаг за кадр ускоряется на быстрых мониторах — так нельзя.
- Берите delta из
clock.getDelta()и умножайте на скорость «в секунду».