Гравитационная симуляция в анимационных системах строится на классическом уравнении движения с постоянным ускорением. Базовая модель описывается через три состояния: положение, скорость и ускорение.
a = g
Ускорение свободного падения в упрощённых 2D/3D сценах принимается как константа, направленная вниз. В контексте анимации знак и величина подбираются эмпирически для достижения визуально правдоподобного поведения.
Дискретная интеграция по времени:
v_{t+t} = v_t + a t
x_{t+t} = x_t + v_t t
Такая схема лежит в основе большинства физически-ориентированных анимационных движков, включая подходы, используемые в popmotion.
В Popmotion физическая анимация реализуется через функцию
physics, которая моделирует движение объекта с начальными
параметрами скорости и ускорения. Основная идея заключается в том, что
разработчик задаёт физические параметры, а система выполняет численное
интегрирование на каждом кадре.
Типичная конфигурация:
import { physics } from '@popmotion/popmotion';
physics({
from: 0,
velocity: -300,
acceleration: 980,
restSpeed: 0.5
}).start(v => {
console.log(v);
});
Здесь:
from — начальная позицияvelocity — начальная скоростьacceleration — постоянное ускорение (гравитация)restSpeed — порог остановки движенияГравитация в таких системах всегда задаётся как положительное ускорение вниз, а направление движения определяется знаком скорости.
Внутри физического цикла Popmotion происходит обновление состояния по аналогии с явным методом Эйлера. Каждый кадр (frame) система вычисляет:
velocity = velocity + acceleration * timeDelta
position = position + velocity * timeDelta
Где timeDelta — интервал времени между кадрами, обычно
нормализованный к 16.67 мс (60 FPS).
Такая модель проста, но требует контроля устойчивости, поскольку при больших значениях ускорения или нестабильном FPS возможны визуальные артефакты.
Базовая реализация падения объекта:
import { physics } from '@popmotion/popmotion';
const gravity = 1200;
physics({
from: 0,
velocity: 0,
acceleration: gravity
}).start(v => {
element.style.transform = `translateY(${v}px)`;
});
Здесь ускорение интерпретируется как постоянная сила, увеличивающая скорость падения. Объект начинает движение из состояния покоя и ускоряется линейно.
Гравитационная симуляция часто расширяется до двумерного пространства. Тогда ускорение применяется только по оси Y, а X-ось управляется отдельной логикой.
physics({
from: { x: 0, y: 0 },
velocity: { x: 150, y: -200 },
acceleration: { x: 0, y: 980 }
}).start(v => {
element.style.transform =
`translate(${v.x}px, ${v.y}px)`;
});
Такой подход позволяет комбинировать гравитацию с инерцией и горизонтальным движением.
Чистая модель гравитации приводит к бесконечному ускорению. Для реалистичности вводится демпфирование, которое имитирует сопротивление воздуха. В Popmotion это может быть реализовано через уменьшение скорости на каждом шаге.
Обобщённая формула с сопротивлением:
v = v (1 - r) + a t
Где r — коэффициент сопротивления.
Практическая реализация:
let velocity = 0;
const gravity = 1200;
const resistance = 0.02;
const update = (dt) => {
velocity = velocity * (1 - resistance) + gravity * dt;
const y = velocity * dt;
element.style.transform = `translateY(${y}px)`;
};
В реальных физических системах скорость падения ограничивается сопротивлением среды. В анимации это используется для предотвращения чрезмерного ускорения.
const terminalVelocity = 1800;
velocity = Math.min(velocity + gravity * dt, terminalVelocity);
Это добавляет визуальную стабильность и предотвращает «разрыв» траектории при длительных анимациях.
Popmotion позволяет комбинировать модели движения. Гравитация может переходить в пружинное движение при достижении границы.
import { physics, spring } from '@popmotion/popmotion';
physics({
from: 0,
velocity: 0,
acceleration: 1200
}).start(v => {
if (v > window.innerHeight) {
spring({
from: v,
to: window.innerHeight - 100,
stiffness: 200
}).start(s => {
element.style.transform = `translateY(${s}px)`;
});
} else {
element.style.transform = `translateY(${v}px)`;
}
});
Такой подход используется для симуляции удара о поверхность с последующим отскоком.
В интерфейсной анимации часто применяется инвертированная ось Y, где положительное направление направлено вниз. Это упрощает интеграцию с DOM, но требует согласованного выбора знаков ускорения.
Если координатная система математическая:
Если DOM:
Несоответствие систем координат является одной из частых причин некорректной анимации.
Корректная гравитационная модель зависит от стабильного
delta time. При нестабильном FPS система начинает вести
себя непредсказуемо.
Нормализация времени:
const dt = Math.min(frameTime, 32) / 1000;
velocity += acceleration * dt;
position += velocity * dt;
Ограничение frameTime предотвращает скачки при лаге.
Гравитация используется не только для визуальных эффектов падения, но и для построения поведенческих моделей:
В каждом случае физическая модель остаётся одинаковой: постоянное ускорение + интеграция скорости + обновление позиции.
Типовой цикл симуляции в Popmotion-подобной системе:
let position = 0;
let velocity = 0;
const acceleration = 980;
function step(dt) {
velocity += acceleration * dt;
position += velocity * dt;
render(position);
}
Этот цикл является базой для любых расширений: сопротивления, столкновений, пружин и ограничения скорости.
При добавлении границ сцены необходимо обрабатывать столкновения:
if (position > ground) {
position = ground;
velocity *= -0.6;
}
Коэффициент отражения управляет потерей энергии при ударе. Это создаёт эффект упругого или демпфированного отскока.
В сложных сценах гравитация применяется одновременно к множеству объектов с независимыми параметрами. Каждое тело имеет:
Хотя базовый Popmotion не требует явного задания массы, её можно эмулировать масштабированием ускорения и скорости.
Добавление массы:
F = m a
В анимационных системах сила гравитации обычно фиксирована, а изменение массы выражается через изменение реакции объекта на ускорение.