Уменьшение числа активных контактов

В физическом движке Oimo.js каждый объект представлен телом (RigidBody), а взаимодействие между телами происходит через контакты. Контакты создаются при столкновении коллайдеров (Collider) и требуют вычисления сил реакции, импульсов и коррекции позиции. С ростом числа активных контактов резко увеличивается нагрузка на CPU, особенно при большом количестве объектов, поэтому важным аспектом оптимизации является уменьшение числа активных контактов без потери корректности симуляции.

Причины большого числа контактов

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

  2. Множественные коллизии одного тела Тело с несколькими коллайдерами или сложной формой может генерировать сразу несколько контактных точек с одним объектом.

  3. Высокая частота симуляции При малом шаге времени симулятор чаще проверяет пересечения, увеличивая количество обнаруженных контактов.

Настройка коллайдеров

Формы коллайдеров сильно влияют на количество контактов:

  • Примитивные коллайдеры (Box, Sphere, Capsule) обрабатываются быстрее и создают меньше контактных точек.
  • Множественные мелкие полигоны создают множество контактных точек, которые часто избыточны для физики.
  • Сложные составные формы можно разбивать на несколько упрощённых примитивов для уменьшения количества контактов.

Пример создания упрощённого коллайдера:

const boxShape = new OIMO.BoxGeometry(1, 1, 1); // Простой куб вместо сложного меша
const boxBody = new OIMO.RigidBody({
  type: 'dynamic',
  shapes: [boxShape],
  position: [0, 5, 0]
});
world.addRigidBody(boxBody);

Фильтры столкновений

Oimo.js поддерживает collision groups и masks, позволяя исключить ненужные проверки. Каждому телу можно задать группу и маску, определяя, с какими объектами оно может сталкиваться:

boxBody.shapes[0].collisionGroup = 1; // Группа объекта
boxBody.shapes[0].collisionMask = 2;  // Маска столкновения

Это уменьшает число активных контактов, исключая столкновения с объектами, которые не влияют на игру или симуляцию.

Упрощение физических слоёв

Разделение объектов на слои активные/пассивные позволяет Oimo.js пропускать вычисления для неподвижных или второстепенных объектов.

  • Пассивные объекты: используют type: 'static', не генерируют контактов, которые требуют вычисления силы.
  • Активные объекты: type: 'dynamic', участвуют в вычислениях.

Пример:

const ground = new OIMO.RigidBody({
  type: 'static',
  shapes: [new OIMO.BoxGeometry(50, 1, 50)],
  position: [0, -0.5, 0]
});
world.addRigidBody(ground);

Настройка параметров мира

Параметры мира влияют на обработку контактов:

  • world.step(dt, velocityIterations, positionIterations) Уменьшение velocityIterations и positionIterations снижает нагрузку, но может ухудшить стабильность симуляции. Оптимизация требует баланса между числом итераций и качеством контактов.

  • world.broadPhase Oimo.js поддерживает разные алгоритмы broad-phase (sweep and prune, grid). Использование сеточной broad-phase уменьшает число проверок столкновений, исключая объекты, которые физически далеко друг от друга.

world.broadPhase = new OIMO.GridBroadPhase();

Контроль активности тел

Oimo.js позволяет отключать обработку некоторых тел через sleeping:

  • Тела, которые находятся в покое, переходят в спящий режим, и контакты для них не вычисляются.
  • Параметры sleepTimeLimit и sleepVelocityLimit регулируют, когда тело считается неактивным:
boxBody.sleepVelocityLimit = 0.1;
boxBody.sleepTimeLimit = 2.0;

Агрегация мелких объектов

Для сцен с множеством мелких объектов лучше объединять их в составные тела:

  • Меньше тел → меньше активных коллайдеров → меньше контактов.
  • Можно использовать compound shapes: несколько примитивов внутри одного тела, которые физически ведут себя как одно.
const compoundBody = new OIMO.RigidBody({ type: 'dynamic' });
compoundBody.addShape(new OIMO.BoxGeometry(1,1,1), [0,0,0]);
compoundBody.addShape(new OIMO.BoxGeometry(1,1,1), [1,0,0]);
world.addRigidBody(compoundBody);

Выводы по оптимизации контактов

  • Применение упрощённых коллайдеров снижает число контактных точек.
  • Использование collision groups и masks исключает ненужные столкновения.
  • Разделение объектов на активные и пассивные уменьшает нагрузку.
  • Включение sleeping для неактивных тел снижает вычисления.
  • Объединение мелких объектов в compound shapes сокращает количество RigidBody и контактов.
  • Настройка broad-phase и числа итераций step позволяет управлять балансом между производительностью и точностью.

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