Туннелирование — это явление, возникающее в физическом движке при моделировании столкновений объектов с высокой скоростью или малым временем кадра. В контексте Ammo.js, JavaScript-обертки над Bullet Physics, туннелирование проявляется, когда объект «пролетает» сквозь другой, не фиксируя столкновение. Причина заключается в том, что стандартная дискретная симуляция проверяет столкновения только в момент обновления кадра, пропуская быстрые объекты между проверками.
В Ammo.js туннелирование особенно актуально для малых, быстрых объектов, таких как пули, шары или элементы динамических симуляций, где точность столкновений критична.
Ammo.js поддерживает два основных подхода к обработке столкновений:
Пример настройки дискретного объекта:
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);
setCcdMotionThreshold и
setCcdSweptSphereRadius.Пример включения CCD:
body.setCcdMotionThreshold(1e-7); // минимальное перемещение для CCD
body.setCcdSweptSphereRadius(0.2); // радиус сферы для проверки траектории
Ключевой момент: масса и размер объекта влияют на
эффективность CCD. Для маленьких быстрых объектов следует
использовать минимально возможный setCcdMotionThreshold и
соответствующий радиус сферы, иначе туннелирование не будет полностью
устранено.
timeStep уменьшает вероятность
пропуска столкновений.stepSimulation принимает три параметра:
timeStep, maxSubSteps,
fixedTimeStep.const deltaTime = clock.getDelta();
physicsWorld.stepSimulation(deltaTime, 10, 1/60);
setCcdMotionThreshold > 0.setCcdSweptSphereRadius выбирается исходя
из физического размера объекта.setLinearVelocity.timeStep.const velocity = body.getLinearVelocity();
const maxSpeed = 50;
if (velocity.length() > maxSpeed) {
velocity.op_mul(maxSpeed / velocity.length());
body.setLinearVelocity(velocity);
}
btCollisionWorld::contactTest.timeStep и радиусах CCD для подбора оптимальных
параметров.Ammo.js предоставляет гибкие инструменты для борьбы с туннелированием, от простого увеличения частоты симуляции до применения непрерывного обнаружения столкновений и оптимизации коллайдеров. Правильная комбинация этих методов позволяет достичь стабильной физики даже в сценах с высокоскоростными объектами.