Gravity симуляции

Гравитационная симуляция в анимационных системах строится на классическом уравнении движения с постоянным ускорением. Базовая модель описывается через три состояния: положение, скорость и ускорение.

a = g

Ускорение свободного падения в упрощённых 2D/3D сценах принимается как константа, направленная вниз. В контексте анимации знак и величина подбираются эмпирически для достижения визуально правдоподобного поведения.

Дискретная интеграция по времени:

v_{t+t} = v_t + a t

x_{t+t} = x_t + v_t t

Такая схема лежит в основе большинства физически-ориентированных анимационных движков, включая подходы, используемые в popmotion.


Физическая система Popmotion и модель physics

В 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 возможны визуальные артефакты.


Имитация гравитации через physics

Базовая реализация падения объекта:

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)`;
};

Ограничение скорости падения (terminal velocity)

В реальных физических системах скорость падения ограничивается сопротивлением среды. В анимации это используется для предотвращения чрезмерного ускорения.

const terminalVelocity = 1800;

velocity = Math.min(velocity + gravity * dt, terminalVelocity);

Это добавляет визуальную стабильность и предотвращает «разрыв» траектории при длительных анимациях.


Использование spring и physics вместе

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, но требует согласованного выбора знаков ускорения.

Если координатная система математическая:

  • вверх: положительное направление Y
  • вниз: отрицательное ускорение

Если DOM:

  • вниз: положительное значение translateY
  • ускорение гравитации положительное

Несоответствие систем координат является одной из частых причин некорректной анимации.


Дискретизация времени и стабильность симуляции

Корректная гравитационная модель зависит от стабильного delta time. При нестабильном FPS система начинает вести себя непредсказуемо.

Нормализация времени:

const dt = Math.min(frameTime, 32) / 1000;
velocity += acceleration * dt;
position += velocity * dt;

Ограничение frameTime предотвращает скачки при лаге.


Применение гравитационной модели в интерфейсах

Гравитация используется не только для визуальных эффектов падения, но и для построения поведенческих моделей:

  • выпадение карточек в интерфейсах drag-and-drop
  • инерционные списки
  • физические меню
  • симуляция разрушения UI-элементов
  • анимация уведомлений

В каждом случае физическая модель остаётся одинаковой: постоянное ускорение + интеграция скорости + обновление позиции.


Обобщённая структура гравитационного цикла

Типовой цикл симуляции в 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

В анимационных системах сила гравитации обычно фиксирована, а изменение массы выражается через изменение реакции объекта на ускорение.