В библиотеке Cannon.js система столкновений строится вокруг объекта контакта — ContactEquation. Каждый экземпляр такого объекта содержит параметры, описывающие конкретную точку соприкосновения двух тел. В рамках одного столкновения может существовать несколько контактных точек.
Контактная точка (ContactPoint) включает:
Эти данные используются решателем (solver) для вычисления импульса, который устраняет пересечение тел и формирует корректную реакцию.
Нормаль контакта — это единичный вектор, направленный от первого тела ко второму и перпендикулярный поверхности столкновения.
В Cannon.js нормаль хранится в свойстве:
contact.ni
где:
ni — normal impulse directionVec3)bi к bjНормаль определяет:
Если два тела пересекаются, импульс будет прикладываться вдоль нормали в противоположном направлении проникновения.
Скалярная проекция относительной скорости на нормаль:
vn = (vj - vi) · ni
где:
vi, vj — скорости тел в точке
контактаni — нормальЕсли vn < 0, тела движутся навстречу друг другу и
требуется реакция.
Нормаль используется:
Глубина проникновения — это величина, на которую объекты пересеклись друг с другом.
В Cannon.js она не хранится напрямую как отдельное поле, а вычисляется через:
penetration внутри алгоритма narrowphaseg в уравнении контактаВ объекте ContactEquation используется выражение:
contact.penetrationVec
или косвенно через вычисление:
g = (xj + rj - xi - ri) · ni
где:
xi, xj — позиции центров массri, rj — локальные радиус-векторы до точки
контактаni — нормальЕсли g < 0, наблюдается проникновение.
Глубина влияет на:
В решателе применяется стабилизация Баумгарте:
bias = -β * penetration / dt
где:
β — коэффициент стабилизацииdt — шаг симуляцииЧем глубже проникновение, тем сильнее корректирующий импульс.
Каждый ContactEquation хранит точки контакта относительно центров масс тел:
contact.ri
contact.rj
где:
ri — вектор от центра масс тела A до точки
контактаrj — аналогично для тела BVec3Это локальные смещения, уже переведённые в мировые координаты.
Мировая точка контакта для тела A:
contactPointA = bodyA.position + ri
Для тела B:
contactPointB = bodyB.position + rj
Эти точки:
Импульс прикладывается не в центр масс, а в точку контакта. Поэтому возникает вращательный эффект.
Крутящий момент вычисляется как:
τ = r × F
где:
r — вектор ri или rjF — импульс вдоль нормалиДаже небольшой импульс может вызвать значительное вращение при большом плече.
При столкновении сложных форм (например, box–box) генерируется несколько контактных точек:
Каждая точка создаёт отдельный ContactEquation.
Одна точка контакта не обеспечивает устойчивость. Например:
Решатель обрабатывает все контакты итеративно.
ContactEquationКонтакт существует только в рамках одного шага симуляции.
После создания нормального контакта создаются уравнения трения:
Касательные вычисляются как ортогональные нормали:
t1 ⟂ ni
t2 = ni × t1
Таким образом, одна точка контакта создаёт:
В Cannon.js можно получить данные контакта через событие:
body.addEventListener("collide", function(event) {
const contact = event.contact;
});
Доступные данные:
contact.nicontact.ricontact.rjcontact.bicontact.bjЭто позволяет:
При малой глубине проникновения возможны:
Причины:
dtworld.solver.iterationscontactEquationStiffnesscontactEquationRelaxationИзбыточные контактные точки увеличивают нагрузку на решатель.
Методы оптимизации:
В Cannon.js часть этой логики реализована в narrowphase.
Для отладки полезно визуализировать:
contactPointA и contactPointBОбычно используется связка с Three.js:
ArrowHelperЭто позволяет анализировать:
Тип формы влияет на способ вычисления контактов:
| Пара форм | Метод вычисления |
|---|---|
| Sphere–Sphere | аналитическая формула |
| Sphere–Plane | проекция центра |
| Box–Box | SAT (Separating Axis Theorem) |
| Convex–Convex | SAT + clipping |
Для convex форм используется алгоритм клиппинга граней, генерирующий множество контактных точек.
Основные поля:
bi, bj — телаni — нормальri, rj — радиус-векторыrestitution — коэффициент упругостиenabled — активность контактаContactEquation наследуется от базового Equation,
который содержит:
minForcemaxForceОбщая формула импульса:
λ = -(Jv + bias) / (JM⁻¹Jᵀ + ε)
где:
J — якобиан (включает нормаль и r × n)M — матрица массε — регуляризацияbias — коррекция проникновенияContactPoint формирует строки якобиана на основе:
Если задан коэффициент упругости:
contact.restitution
то учитывается относительная скорость вдоль нормали:
vn_after = -restitution * vn_before
Это влияет только на компонент вдоль ni.
ContactPoint является ключевым элементом системы столкновений:
Понимание структуры ContactEquation позволяет:
Глубокое понимание нормали, глубины проникновения и контактных точек необходимо для точной настройки физики в реальном времени и построения устойчивых трёхмерных сцен.