Cannon.js использует дискретную симуляцию физики, где состояние мира обновляется шаг за шагом. Каждый шаг называется временным шагом (time step), и его величина критически влияет на точность и стабильность симуляции.
const timeStep = 1 / 60; // 60 кадров в секунду
world.step(timeStep);
Для плавного взаимодействия с разными частотами обновления экрана используется адаптивный шаг. Он позволяет разделить реальное прошедшее время на несколько фиксированных шагов симуляции:
let lastTime;
function animate(time) {
if (!lastTime) lastTime = time;
const dt = (time - lastTime) / 1000; // конвертация в секунды
lastTime = time;
const fixedTimeStep = 1 / 60;
const maxSubSteps = 3;
world.step(fixedTimeStep, dt, maxSubSteps);
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
Параметры функции
world.step(fixedTimeStep, dt, maxSubSteps):
fixedTimeStep — основной шаг симуляции.dt — реальное время, прошедшее с предыдущего
кадра.maxSubSteps — максимальное число шагов, которые можно
сделать за один кадр для компенсации задержек.Особенности:
dt меньше fixedTimeStep, симуляция
пропускает шаг.dt больше, Cannon.js делает несколько шагов, пока
не достигнет актуального времени.maxSubSteps предотвращает перегрузку
CPU.Поскольку симуляция и рендер работают с разными частотами, появляется разрыв между текущим состоянием объектов и кадром. Для сглаживания движения используется интерполяция.
const alpha = (dt % fixedTimeStep) / fixedTimeStep;
mesh.position.lerp(body.previousPosition, body.position, alpha);
mesh.quaternion.slerp(body.previousQuaternion, body.quaternion, alpha);
alpha — доля между предыдущим и текущим
состоянием.lerp (Linear Interpolation) — линейная интерполяция
позиции.slerp (Spherical Linear Interpolation) — интерполяция
ориентации (кватернионов).Эффект интерполяции:
previousPosition, previousQuaternion)
обязательно для корректной интерполяции.fixedTimeStep до 1/120 или
1/240.Cannon.js позволяет синхронизировать физику с реальным временем, что важно для сетевых игр и VR:
maxSubSteps.При интеграции с Three.js или другими рендеринг-библиотеками:
function updateMeshFromBody(mesh, body, alpha) {
mesh.position.copy(body.previousPosition).lerp(body.position, alpha);
mesh.quaternion.copy(body.previousQuaternion).slerp(body.quaternion, alpha);
}
Для соединений (constraints) и многочастичных тел:
maxSubSteps улучшается стабильность
соединений при резких движениях.Использование фиксированного шага, адаптивного обновления и интерполяции обеспечивает одновременно точность физической модели и плавность визуализации, что делает Cannon.js надёжным инструментом для интерактивных 3D-приложений.