Туннелирование и способы борьбы с ним

Туннелирование — это явление, возникающее в физическом движке при моделировании столкновений объектов с высокой скоростью или малым временем кадра. В контексте Ammo.js, JavaScript-обертки над Bullet Physics, туннелирование проявляется, когда объект «пролетает» сквозь другой, не фиксируя столкновение. Причина заключается в том, что стандартная дискретная симуляция проверяет столкновения только в момент обновления кадра, пропуская быстрые объекты между проверками.

В Ammo.js туннелирование особенно актуально для малых, быстрых объектов, таких как пули, шары или элементы динамических симуляций, где точность столкновений критична.


Дискретная и непрерывная коллизия

Ammo.js поддерживает два основных подхода к обработке столкновений:

Дискретная коллизия (Discrete Collision Detection)

  • На каждом шаге симуляции проверяется пересечение объектов в текущих положениях.
  • Эффективна для большинства сцен с умеренной скоростью объектов.
  • Основной недостаток — пропуск столкновений при больших скоростях (туннелирование).

Пример настройки дискретного объекта:

const shape = new Ammo.btBoxShape(new Ammo.btVector3(1, 1, 1));
const mass = 1;
const transform = new Ammo.btTransform();
transform.setIdentity();
transform.setOrigin(new Ammo.btVector3(0, 10, 0));

const localInertia = new Ammo.btVector3(0, 0, 0);
shape.calculateLocalInertia(mass, localInertia);

const motionState = new Ammo.btDefaultMotionState(transform);
const rbInfo = new Ammo.btRigidBodyConstructionInfo(mass, motionState, shape, localInertia);
const body = new Ammo.btRigidBody(rbInfo);
physicsWorld.addRigidBody(body);

Непрерывная коллизия (Continuous Collision Detection, CCD)

  • Позволяет отслеживать объекты между шагами симуляции.
  • Использует swept collision shapes, проверяя траекторию движения.
  • В Ammo.js CCD активируется через методы setCcdMotionThreshold и setCcdSweptSphereRadius.

Пример включения CCD:

body.setCcdMotionThreshold(1e-7); // минимальное перемещение для CCD
body.setCcdSweptSphereRadius(0.2); // радиус сферы для проверки траектории

Ключевой момент: масса и размер объекта влияют на эффективность CCD. Для маленьких быстрых объектов следует использовать минимально возможный setCcdMotionThreshold и соответствующий радиус сферы, иначе туннелирование не будет полностью устранено.


Техники борьбы с туннелированием

1. Увеличение частоты шагов симуляции

  • Симуляция с меньшим timeStep уменьшает вероятность пропуска столкновений.
  • В Ammo.js метод stepSimulation принимает три параметра: timeStep, maxSubSteps, fixedTimeStep.
const deltaTime = clock.getDelta();
physicsWorld.stepSimulation(deltaTime, 10, 1/60);
  • maxSubSteps позволяет разделить большой кадр на несколько внутренних шагов, повышая точность столкновений.

2. Использование CCD для быстрых объектов

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

3. Оптимизация формы коллайдера

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

4. Ограничение скорости объектов

  • В некоторых сценах целесообразно лимитировать максимальную скорость через setLinearVelocity.
  • Это уменьшает вероятность туннелирования без необходимости уменьшать timeStep.
const velocity = body.getLinearVelocity();
const maxSpeed = 50;
if (velocity.length() > maxSpeed) {
    velocity.op_mul(maxSpeed / velocity.length());
    body.setLinearVelocity(velocity);
}

Проверка эффективности CCD

  • Визуальная отладка: трассировка объектов между кадрами для проверки пересечений.
  • Логирование столкновений: Ammo.js позволяет получать коллизионные события через btCollisionWorld::contactTest.
  • Тесты скорости: имитация движения объектов на различных timeStep и радиусах CCD для подбора оптимальных параметров.

Советы по производительности

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

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