В Ammo.js обработка контактов между телами в физическом
мире происходит через коллбэки, один из которых —
onContactProcessed. Этот метод используется для получения
информации о столкновениях и, при необходимости, вмешательства в
физические расчёты на уровне контакта. Основное назначение —
кастомизация реакции объектов на столкновение без модификации всей
симуляции.
onContactProcessed вызывается для каждой пары
контактирующих объектов после того, как Bullet вычислил
контактные точки, нормали и импульсы, но до применения их к объектам.
Функция имеет сигнатуру:
function onContactProcessed(cp, colObj0Wrap, colObj1Wrap) { ... }
cp (ContactPoint) — объект, содержащий
данные о точке контакта: позицию, нормаль, импульс, глубину
проникновения.colObj0Wrap / colObj1Wrap
(CollisionObjectWrapper) — обёртки для тел, участвующих в
контакте. Через них можно получить физические объекты
btRigidBody и их свойства.Контактная точка предоставляет доступ к ключевым параметрам:
let position = cp.get_m_positionWorldOnA();
let normal = cp.get_m_normalWorldOnB();
let distance = cp.get_m_distance1();
get_m_positionWorldOnA() и
get_m_positionWorldOnB() возвращают вектор
позиции контакта в мировых координатах для объектов A и B.get_m_normalWorldOnB() — нормаль
контакта, направленная от объекта B к объекту A.get_m_distance1() — глубина
проникновения (отрицательная при пересечении).Изменять напрямую нормаль и позицию нежелательно, но можно влиять на силы, которые применяются к телам:
let impulse = cp.getAppliedImpulse();
cp.setAppliedImpulse(impulse * 0.5);
Это позволяет реализовать эффекты «мягких столкновений» или кастомной амортизации.
Чтобы коллбэк работал, его необходимо зарегистрировать для
btCollisionObject или btRigidBody. Пример для
btRigidBody:
let body = new Ammo.btRigidBody(rbInfo);
body.setContactProcessingThreshold(0.1); // минимальное расстояние для обработки контакта
body.onContactProces sed = function(cp, colObj0Wrap, colObj1Wrap) {
let normal = cp.get_m_normalWorldOnB();
let impulse = cp.getAppliedImpulse();
if (impulse > 10) {
console.log('Сильный удар', impulse, normal.x(), normal.y(), normal.z());
}
return true; // true — разрешить физическую обработку
};
setContactProcessingThreshold —
определяет минимальное расстояние до столкновения, при котором будет
вызван коллбэк.true/false
определяет, будет ли Bullet применять стандартные физические силы после
вызова коллбэка. Возврат false позволяет полностью
перехватить обработку контакта.cp.setAppliedImpulse(Math.min(cp.getAppliedImpulse(), 5));
if (colObj0Wrap.getCollisionObject().getUserIndex() === 1 &&
colObj1Wrap.getCollisionObject().getUserIndex() === 2) {
return false; // контакт не обрабатывается физикой
}
let force = cp.getAppliedImpulse();
if (force > 15) {
spawnParticles(cp.get_m_positionWorldOnA(), force);
}
onContactProcessed вызывается каждую
симуляционную итерацию для всех активных контактов, поэтому
тяжёлая логика в коллбэке может серьёзно замедлить симуляцию.setContactProcessingThreshold, иначе
некоторые контакты не будут передаваться коллбэку.Коллбэк работает в контексте btDiscreteDynamicsWorld и
реагирует на все объекты, зарегистрированные в этом мире. Пример
установки нескольких объектов с разными обработчиками:
let world = new Ammo.btDiscreteDynamicsWorld(...);
let boxBody = createRigidBody(boxShape, mass, position);
let sphereBody = createRigidBody(sphereShape, mass, position);
boxBody.onContactProces sed = handleBoxContacts;
sphereBody.onContactProces sed = handleSphereContacts;
world.addRigidBody(boxBody);
world.addRigidBody(sphereBody);
Это позволяет задавать уникальное поведение для каждого типа объекта и создавать гибкую систему реакции на столкновения.
onContactProcessed предоставляет мощный механизм
вмешательства в физическую симуляцию на уровне отдельных точек контакта.
Управление импульсами, фильтрация взаимодействий и генерация событий —
всё это возможно без изменения ядра симулятора. Правильное использование
этого метода позволяет создавать реалистичную динамику и контролируемые
реакции объектов в Ammo.js.