В основе библиотеки Oimo.js лежит чёткая модель разделения
ответственности между четырьмя ключевыми сущностями:
- World — физический мир и симуляция
- Body — физическое тело
- Shape — геометрическая форма тела
- Joint — ограничение или связь между телами
Понимание их взаимосвязи определяет корректную архитектуру сцены,
производительность и стабильность расчётов.
World — центр управления
симуляцией
World является контейнером всей физической сцены. Он
отвечает за:
- хранение всех тел и соединений,
- интеграцию движения,
- обработку столкновений,
- решение ограничений,
- гравитацию,
- шаг симуляции.
Основные обязанности World
Хранение объектов
- Массив тел
- Массив соединений
- Контактные пары
Физический шаг
- Вычисление сил
- Интеграция скоростей
- Обнаружение столкновений
- Разрешение контактов
- Решение ограничений Joint
Глобальные параметры
- Вектор гравитации
- Итерации решателя
- Параметры широкофазной проверки
Связи World
World
├── Body
│ └── Shape
└── Joint (соединяет Body ↔ Body)
World управляет всеми Body и Joint, но не владеет
Shape напрямую — формы принадлежат телам.
Body — физический
носитель массы и движения
Body представляет физический объект с положением,
ориентацией, массой и скоростью. Однако геометрии внутри него нет — она
задаётся через Shape.
Что содержит Body
- Позиция (Vector3)
- Кватернион вращения
- Линейная скорость
- Угловая скорость
- Масса
- Матрица инерции
- Список Shape
- Флаги состояния (static, dynamic, kinematic)
Типы тел
Dynamic
- Подчиняется гравитации
- Участвует в столкновениях
- Может двигаться
Static
- Бесконечная масса
- Не двигается
- Используется для пола, стен
Kinematic
- Движется вручную
- Не подчиняется силам
- Влияет на другие тела
Связь Body с World
При добавлении тела в мир:
world.add(body);
- Body регистрируется в World
- Создаётся прокси для broad-phase
- Тело включается в цикл симуляции
Удаление происходит аналогично.
Shape — геометрическая
составляющая тела
Shape описывает форму, по которой
рассчитываются:
- столкновения
- объём
- инерция
- центр масс
Важная особенность
Body может содержать несколько Shape. Это
позволяет:
- создавать составные объекты,
- смещать центр масс,
- строить сложные формы из простых примитивов.
Поддерживаемые формы
- Box
- Sphere
- Cylinder
- Capsule
- Convex
Связь Shape → Body
Shape не существует самостоятельно. Она:
- создаётся,
- добавляется к Body,
- учитывается при расчёте массы.
body.addShape(shape);
После добавления:
- Пересчитывается масса тела.
- Пересчитывается тензор инерции.
- Обновляется AABB.
Локальное преобразование
Shape
Каждая Shape имеет:
- локальную позицию внутри Body,
- локальную ориентацию.
Таким образом:
Мировая трансформация Shape =
Трансформация Body +
Локальная трансформация Shape
Это позволяет создавать, например, Т-образные или L-образные
конструкции.
Joint — ограничение между
телами
Joint связывает два Body и ограничивает их
относительное движение.
Основные функции Joint
- фиксация расстояния,
- ограничение вращения,
- создание шарниров,
- моделирование пружин,
- имитация механических систем.
Структура Joint
Joint всегда содержит:
- body1
- body2
- параметры ограничения
- якорные точки
Типы соединений
- DistanceJoint
- HingeJoint
- SliderJoint
- BallAndSocketJoint
- PrismaticJoint
Каждый тип накладывает определённые математические ограничения на
движение тел.
Взаимодействие во время
шага симуляции
Внутри метода world.step() происходит последовательность
действий:
1. Применение гравитации к
Body
Dynamic-тела получают ускорение.
2. Broad-phase
Используются AABB Shape для поиска потенциальных столкновений.
3. Narrow-phase
Выполняется точный расчёт контактов между Shape разных тел.
4. Генерация контактных
ограничений
Создаются временные структуры контакта.
5. Решение ограничений
Решатель обрабатывает:
- контактные ограничения,
- ограничения Joint.
6. Интеграция скоростей и
позиций
Обновляются:
- позиция Body,
- ориентация Body.
Shape автоматически следуют за Body.
Иерархия владения
Уровень 1 — World
Хранит:
Уровень 2 — Body
Хранит:
Уровень 3 — Shape
Не владеет другими сущностями.
Joint
Не принадлежит Body, а регистрируется в World и содержит ссылки на
два Body.
Контактная модель:
как Shape влияет на Body
Когда две Shape сталкиваются:
- Вычисляется точка контакта.
- Рассчитывается нормаль.
- Определяется глубина проникновения.
- Формируется контактное ограничение.
Далее:
- Контакт влияет на скорость Body.
- Body изменяет положение.
- Shape получают новую мировую позицию через Body.
Таким образом Shape является геометрическим интерфейсом, а Body —
физическим контейнером состояния.
Масса и инерция: роль
Shape в расчётах
При добавлении нескольких Shape к одному Body:
Итоговая масса = сумма масс Shape
Центр масс = взвешенное среднее
Тензор инерции = сумма инерций с учётом смещения
Это означает:
- геометрия влияет на физику,
- изменение Shape меняет поведение Body,
- Joint опираются на центр масс тел.
Связь Joint с Body и World
Joint регистрируется в World:
world.add(joint);
Во время шага симуляции:
- Joint получает текущие трансформации Body.
- Вычисляется ошибка ограничения.
- Решатель корректирует скорости Body.
Важно, что Joint не управляет Shape напрямую — он воздействует
исключительно на Body.
Пространственные зависимости
| Сущность |
Имеет позицию |
Имеет массу |
Участвует в столкновениях |
Участвует в решателе |
| World |
Нет |
Нет |
Управляет процессом |
Да |
| Body |
Да |
Да |
Да |
Да |
| Shape |
Локально |
Через Body |
Да |
Через Body |
| Joint |
Через Body |
Нет |
Нет |
Да |
Типичный жизненный цикл
объекта
- Создаётся World.
- Создаётся Body.
- К Body добавляется Shape.
- Body добавляется в World.
- При необходимости создаётся Joint.
- Joint добавляется в World.
- Выполняется
world.step() в цикле.
Удаление происходит в обратном порядке:
- удаление Joint,
- удаление Body,
- очистка World.
Практическая
архитектурная модель сцены
В сложных проектах используется следующая логика:
- Графическая модель (Three.js, Babylon.js и др.)
- Отдельная физическая модель на основе Oimo.js
- Связь через синхронизацию позиции и кватерниона
ThreeMesh.position ← Body.position
ThreeMesh.quaternion ← Body.quaternion
Shape остаются полностью невидимыми для рендера.
Ошибки
проектирования при работе с этими сущностями
1. Создание Body без Shape
Такое тело не участвует в столкновениях.
2. Частое пересоздание World
Нарушает производительность.
3. Изменение
геометрии Shape без пересчёта массы
Приводит к некорректной физике.
4. Прямое изменение позиции
Shape
Не влияет на мир — управлять нужно через Body.
Ключевые принципы
взаимосвязи
- World управляет всем.
- Body содержит физическое состояние.
- Shape определяет форму и столкновения.
- Joint ограничивает движение между Body.
- Shape никогда не существуют вне Body.
- Joint никогда не существуют вне World.
- Все вычисления происходят в World.
Ментальная модель системы
- World — сцена и движок.
- Body — физический актёр.
- Shape — его геометрия.
- Joint — механическая связь между актёрами.
Эта иерархия формирует устойчивую, масштабируемую архитектуру
физической симуляции в Oimo.js, где каждая сущность имеет строго
определённую роль и взаимодействует с другими через чётко ограниченные
механизмы.