Runtime-анимация через setInterval и deltaTime

Для создания анимаций в Babylon.js, зачастую применяется техника обновления сцены с использованием временных интервалов и расчёта времени между кадрами. Одним из таких подходов является использование функции setInterval совместно с параметром deltaTime. Это позволяет контролировать скорость анимации, плавность её выполнения и корректную синхронизацию движения объектов в зависимости от времени.

Что такое deltaTime?

deltaTime — это разница во времени между текущим и предыдущим кадром. Он выражается в миллисекундах и является важнейшей величиной для того, чтобы анимации и физические симуляции выглядели реалистично, независимо от частоты кадров. Если используется переменная deltaTime, она позволяет избежать зависимость анимаций от частоты кадров.

В Babylon.js часто используется это значение для обеспечения независимости анимаций от производительности устройства. Для корректной работы анимации и движения объектов нужно учитывать скорость их изменения не в абсолютных значениях, а относительно времени, прошедшего с последнего обновления. Это позволяет избежать скачков и залипаний в анимациях, что особенно важно при рендеринге в реальном времени.

Использование setInterval для анимации

setInterval — стандартная функция JavaScript, которая позволяет выполнять функцию через определённые интервалы времени. Для анимации она используется с целью обновления сцены на регулярной основе. В контексте Babylon.js, setInterval можно применить для создания анимаций, однако стоит учитывать его особенности, такие как возможная неточность в интервалах времени и нагрузка на процессор.

Пример использования setInterval для анимации в Babylon.js:

const scene = new BABYLON.Scene(engine);
const camera = new BABYLON.ArcRotateCamera("camera1", Math.PI / 2, Math.PI / 2, 10, BABYLON.Vector3.Zero(), scene);
camera.attachControl(canvas, true);

const box = BABYLON.MeshBuilder.CreateBox("box", { size: 1 }, scene);

let lastTime = performance.now();

setInterval(() => {
    const currentTime = performance.now();
    const deltaTime = (currentTime - lastTime) / 1000;
    lastTime = currentTime;

    // Обновление позиции коробки
    box.position.x += deltaTime * 2;  // Скорость движения зависит от времени

    scene.render();
}, 16);  // Примерно 60 кадров в секунду

В этом примере каждое обновление сцены происходит примерно каждые 16 миллисекунд (что соответствует 60 кадрам в секунду). Важно заметить, что движение объекта (box.position.x) зависит от времени, прошедшего с последнего кадра, что гарантирует плавность анимации, даже если частота кадров варьируется.

Плюсы и минусы использования setInterval

Использование setInterval имеет свои плюсы и минусы в контексте анимации.

Плюсы:

  1. Простота реализации: Не требуется сложных механик для синхронизации анимации.
  2. Частота кадров: Можно чётко задать интервал времени между кадрами, что позволяет контролировать частоту рендеринга.

Минусы:

  1. Погрешности в интервалах: setInterval может не обеспечивать точные интервалы времени, особенно если браузер испытывает нагрузку. Это может привести к нестабильности анимации.
  2. Отсутствие синхронизации с основной петлёй рендеринга: Babylon.js использует собственную систему рендеринга, и использование setInterval может привести к рассогласованию между кадрами, что может сделать анимацию менее плавной.

Преимущества использования встроенной системы анимаций Babylon.js

Вместо использования setInterval, Babylon.js предлагает встроенную систему анимации, которая использует события обновления сцены, такие как scene.registerBeforeRender. Это позволяет синхронизировать анимации с основной петлёй рендеринга, устраняя проблемы, связанные с неточной синхронизацией времени.

Пример реализации с использованием встроенной анимации:

const scene = new BABYLON.Scene(engine);
const camera = new BABYLON.ArcRotateCamera("camera1", Math.PI / 2, Math.PI / 2, 10, BABYLON.Vector3.Zero(), scene);
camera.attachControl(canvas, true);

const box = BABYLON.MeshBuilder.CreateBox("box", { size: 1 }, scene);

scene.registerBeforeRender(function () {
    const deltaTime = engine.getDeltaTime() / 1000;  // Получение deltaTime, делённого на 1000 для перевода в секунды
    box.position.x += deltaTime * 2;  // Скорость движения объекта
});

Этот подход имеет несколько важных преимуществ:

  • Точная синхронизация с рендерингом: Обновление сцены и анимации происходит в одном потоке, что позволяет избежать рассинхронизации.
  • Отсутствие погрешностей в интервалах времени: Babylon.js автоматически учитывает переменную частоту кадров и использует оптимизированную систему рендеринга.

Сравнение методов

Характеристика setInterval Встроенная анимация Babylon.js
Синхронизация с рендерингом Нет Да
Точность интервалов Могут быть погрешности Высокая точность
Простота реализации Простая Требуется использование метода registerBeforeRender
Процессорная нагрузка Может быть высокой Оптимизировано для рендеринга
Плавность анимации Зависит от производительности устройства Обычно более плавная

Использование setInterval может быть подходящим для простых анимаций или временных эффектов, но для более сложных и требовательных к производительности задач лучше использовать механизмы, встроенные в Babylon.js.

Заключение

Для создания анимаций с учётом времени в Babylon.js можно использовать как стандартную функцию setInterval, так и встроенные методы для регистрации обновлений сцены. В то время как использование setInterval подходит для простых задач, использование registerBeforeRender из Babylon.js обеспечивает более высокую точность и синхронизацию с рендерингом, что важно для создания плавных и стабильных анимаций в реальном времени.