Версии библиотеки: различия между 1.x и 2.x

Oimo.js — это JavaScript-порт физического движка OimoPhysics, предназначенный для расчёта твёрдотельной динамики в браузере. Библиотека ориентирована на моделирование жёстких тел, столкновений и ограничений (constraints) и широко применяется совместно с WebGL-рендерами, в частности с Three.js.

Переход от ветки 1.x к 2.x стал не косметическим обновлением, а фактически переработкой архитектуры, API и внутреннего ядра. Версия 2.x упростила структуру кода, улучшила производительность и изменила принципы конфигурации мира и тел.


Архитектурные различия

Структура ядра

В версии 1.x библиотека имела более сложную и громоздкую архитектуру, во многом унаследованную от оригинального C++-движка. Код содержал большое количество низкоуровневых классов и вспомогательных структур, что затрудняло понимание и сопровождение.

Версия 2.x была переработана с акцентом на:

  • уменьшение объёма кода,
  • устранение избыточных абстракций,
  • упрощение зависимостей между компонентами,
  • более явное разделение логики мира, тел и коллизий.

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


Изменения API

Создание физического мира

В 1.x мир создавался через конструктор с передачей конфигурационного объекта:

var world = new OIMO.World({
    timestep: 1/60,
    iterations: 8,
    broadphase: 2,
    worldscale: 1,
    gravity: [0, -9.8, 0]
});

Конфигурация включала параметры broadphase, масштабирования и числа итераций солвера.

В 2.x API стало более лаконичным:

var world = new OIMO.World({
    gravity: [0, -9.8, 0]
});

Некоторые параметры получили значения по умолчанию, а сложные настройки были скрыты от базового уровня использования.

Ключевое отличие: 2.x делает упор на минимальный конфигурационный вход, снижая порог вхождения.


Добавление тел (Rigid Bodies)

В ветке 1.x тела создавались через универсальный метод world.add(), в который передавался большой конфигурационный объект:

world.add({
    type: 'box',
    size: [1, 1, 1],
    pos: [0, 10, 0],
    move: true,
    density: 1
});

В 2.x структура параметров была упрощена и унифицирована. Некоторые свойства были переименованы, а логика движения стала более прозрачной:

world.add({
    type: 'box',
    size: [1, 1, 1],
    pos: [0, 10, 0],
    density: 1
});

Флаг move был заменён на более явную модель: статическое тело определяется через density: 0.

Отличие 2.x: устранение дублирующих параметров и переход к физически корректной модели через плотность.


Изменения в системе коллизий

Broadphase

В версии 1.x можно было выбирать тип broadphase через числовой параметр:

  • 1 — brute force
  • 2 — sweep and prune
  • 3 — dynamic bounding volume tree

В 2.x выбор broadphase чаще всего осуществляется автоматически. Разработчики библиотеки сделали акцент на оптимизированном варианте по умолчанию, устранив необходимость ручной настройки в большинстве случаев.

Это снизило гибкость, но повысило стабильность и предсказуемость поведения.


Обработка контактов

В 1.x система контактов была более детализированной, но сложной. Доступ к контактным данным требовал обхода внутренних структур:

var contact = world.contacts;
while(contact){
    // обработка
    contact = contact.next;
}

В 2.x интерфейс работы с контактами стал более упорядоченным, внутренние цепочки были оптимизированы, а структура данных стала легче для анализа.

Основные изменения:

  • упрощение списка контактов,
  • более стабильная обработка касаний,
  • улучшение устойчивости при множественных столкновениях.

Ограничения (Constraints)

Версия 1.x поддерживала базовые типы ограничений:

  • шарнирные (hinge),
  • дистанционные (distance),
  • шаровые (ball-and-socket).

В 2.x механизм ограничений был переработан для повышения численной устойчивости. Основные изменения:

  • улучшенная стабилизация шарниров,
  • корректная работа при больших массах,
  • снижение «дрожания» объектов.

Внутренний солвер стал более эффективным, что особенно заметно при большом количестве соединённых тел.


Производительность

Оптимизация памяти

В 1.x активно использовались объекты JavaScript, что приводило к частым выделениям памяти и нагрузке на сборщик мусора.

В 2.x была внедрена стратегия:

  • повторного использования объектов,
  • более компактных структур данных,
  • сокращения временных аллокаций.

Это значительно уменьшило количество GC-паузы в сложных сценах.


Численная стабильность

В 1.x при большом количестве тел могли наблюдаться:

  • накопление ошибок,
  • нестабильные вращения,
  • «взрывы» системы при высоких скоростях.

Версия 2.x улучшила:

  • интегратор,
  • коррекцию проникновения,
  • порядок решения ограничений.

Результат — более предсказуемое поведение в динамических сценах.


Работа с масштабом мира

В 1.x присутствовал параметр worldscale, позволяющий изменять масштаб симуляции. Это часто использовалось для адаптации физических величин к визуальной сцене.

В 2.x данный параметр был исключён или существенно упрощён. Разработчики сделали ставку на использование реальных единиц измерения и корректную настройку размеров объектов.

Изменение философии:

  • 1.x — гибкая настройка масштаба.
  • 2.x — строгая физическая согласованность.

Поддержка модульности и сборщиков

Версия 1.x чаще подключалась как глобальный скрипт:

<script src="oimo.min.js"></script>

В 2.x улучшена совместимость с:

  • ES6-модулями,
  • системами сборки (Webpack, Rollup),
  • современными структурами проектов.

Это упрощает интеграцию в сложные приложения.


Изменения в именовании и структуре классов

В ветке 1.x многие классы имели длинные и не всегда интуитивные названия, отражающие внутреннюю структуру физического ядра.

В 2.x наблюдается:

  • унификация имён,
  • сокращение вложенности,
  • более прямой доступ к свойствам тел.

Например, доступ к позиции и вращению стал проще и логичнее, что облегчает синхронизацию с графическими объектами.


Обратная совместимость

Миграция с 1.x на 2.x не является полностью совместимой:

  • изменены параметры создания тел,
  • удалены или переименованы свойства,
  • изменена логика статических объектов,
  • упрощён механизм конфигурации мира.

Старый код требует адаптации, особенно в частях, где использовались расширенные параметры broadphase или нестандартные ограничения.


Поведение статических и динамических тел

В 1.x динамичность объекта определялась флагом move.

В 2.x:

  • density > 0 — динамическое тело,
  • density = 0 — статическое тело.

Такой подход соответствует физической модели твёрдотельной динамики и делает API более логичным.


Работа с вращениями

Версия 1.x иногда демонстрировала нестабильность при сложных вращениях и комбинациях сил.

В 2.x улучшены:

  • кватернионные вычисления,
  • интеграция угловых скоростей,
  • устойчивость при длительной симуляции.

Это особенно важно для механических конструкций и сложных систем ограничений.


Сравнительная характеристика

Характеристика 1.x 2.x
Архитектура Более громоздкая Упрощённая
Настройка мира Расширенная Минималистичная
Broadphase Выбирается вручную Оптимальный по умолчанию
Статические тела Флаг move density = 0
Производительность Ниже при больших сценах Выше и стабильнее
Совместимость Глобальный скрипт Поддержка модулей
Численная устойчивость Средняя Повышенная

Практические выводы о различиях

Версия 1.x предоставляет больше низкоуровневого контроля, но требует глубокого понимания внутренней структуры движка. Она подходит для проектов, где важна гибкость и возможность тонкой настройки.

Версия 2.x ориентирована на:

  • чистый API,
  • производительность,
  • стабильность,
  • современную интеграцию в JavaScript-экосистему.

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