Производительность World: ограничение итераций решателя

Cannon.js предоставляет мощный физический движок для симуляции твёрдого тела в браузере на JavaScript. Один из ключевых аспектов оптимизации производительности — правильная конфигурация World и итераций решателя. Неправильные настройки могут привести к снижению FPS и нестабильности симуляции, особенно при большом количестве объектов.


Объект World и его свойства

Объект CANNON.World является центральным элементом симуляции. Он управляет всеми телами, коллайдерами и взаимодействиями. Основные свойства, влияющие на производительность:

  • gravity – вектор гравитации (CANNON.Vec3).
  • broadphase – стратегия широкого поиска столкновений. Доступны NaiveBroadphase и SAPBroadphase. SAP (Sweep and Prune) более эффективен для большого числа тел.
  • solver – объект решателя (CANNON.GSSolver), который вычисляет реакции сил между телами.
  • solver.iterations – количество итераций решателя за один шаг симуляции. Увеличение значения повышает точность, но снижает производительность.
  • solver.tolerance – допустимая погрешность при решении ограничений. Меньшие значения повышают точность контактов, но увеличивают нагрузку на CPU.

Пример базовой настройки World:

const world = new CANNON.World();
world.gravity.set(0, -9.82, 0);
world.broadphase = new CANNON.SAPBroadphase(world);
world.solver.iterations = 10;
world.solver.tolerance = 0.001;

Ограничение итераций решателя

Каждый шаг физической симуляции включает решение системы ограничений (constraints) для всех взаимодействующих тел. Решатель (Solver) выполняет итерации, чтобы приблизить решения к реальному физическому поведению.

  • Высокое количество итераций

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

    • Уменьшает нагрузку на CPU.
    • Может привести к «проваливанию» тел сквозь друг друга или нестабильной симуляции.

Баланс между точностью и производительностью достигается экспериментально. Для большинства браузерных игр достаточно 5–10 итераций.

Пример ограничения итераций:

world.solver.iterations = 5; // минимальная нагрузка, базовая точность
world.solver.tolerance = 0.01; // допустимая погрешность для ускорения симуляции

Влияние Broadphase на нагрузку

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

  • NaiveBroadphase Проверяет все пары объектов, что даёт сложность O(n²). Подходит для малого количества тел.

  • SAPBroadphase Оптимизирован для длинных сцен с множеством объектов. Работает по принципу сортировки тел вдоль оси и проверки только потенциально пересекающихся.

Комбинация SAPBroadphase и уменьшенного количества итераций решателя обеспечивает заметное повышение FPS без критической потери точности.

world.broadphase = new CANNON.SAPBroadphase(world);
world.solver.iterations = 7;

Настройка фиксированного шага симуляции

Cannon.js позволяет контролировать частоту обновления физики через fixedTimeStep:

const timeStep = 1 / 60; // 60 шагов в секунду

function updatePhysics(deltaTime) {
    world.step(timeStep, deltaTime, 3); // последняя цифра – maxSubSteps
}
  • maxSubSteps – максимальное количество подшагов за один кадр.

    • Позволяет сглаживать движение при колебаниях FPS.
    • Ограничение подшагов предотвращает резкий рост нагрузки при падении частоты кадров.

Оптимальное сочетание: умеренное количество итераций решателя + SAPBroadphase + ограничение maxSubSteps.


Практические рекомендации по оптимизации

  1. Минимизировать количество итераций решателя до минимально приемлемого уровня для стабильности.
  2. Использовать SAPBroadphase для больших сцен с сотнями тел.
  3. Контролировать maxSubSteps и fixedTimeStep для плавного обновления физики.
  4. Настраивать solver.tolerance, увеличивая её для ускорения симуляции, если абсолютная точность не критична.
  5. Группировать статические объекты и уменьшать число подвижных тел, чтобы сократить количество ограничений.

Примеры динамического управления производительностью

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

function adjustSolverFPS(currentFPS) {
    if (currentFPS < 30) {
        world.solver.iterations = 3; // минимальная нагрузка
    } else if (currentFPS < 50) {
        world.solver.iterations = 5; // средняя точность
    } else {
        world.solver.iterations = 10; // максимальная точность
    }
}

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


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