Якорные точки в локальных координатах

В Cannon.js локальные координаты играют ключевую роль при работе с телами и соединениями, особенно когда речь идёт о Constraint (связях) и точках крепления. Локальные координаты позволяют задавать положение точки относительно центра масс тела, а не в глобальной системе сцены, что делает управление сложными конструкциями более предсказуемым и стабильным.

Понятие якорной точки

Якорная точка — это точка на теле, к которой прикрепляется соединение, такое как PointToPointConstraint или HingeConstraint. Она задаётся в локальных координатах тела:

const localAnchor = new CANNON.Vec3(1, 0, 0);

Здесь (1, 0, 0) обозначает, что точка находится на 1 единицу вдоль оси X относительно центра масс тела. Использование локальных координат обеспечивает независимость соединения от позиции и ориентации тела в мире.

Локальные координаты vs глобальные

  • Локальные координаты — позиция относительно центра масс тела.
  • Глобальные координаты — абсолютная позиция в мировой системе сцены.

Преимущество локальных координат заключается в том, что при вращении или перемещении тела точка соединения остаётся фиксированной относительно тела, что важно для динамических симуляций.

Создание и использование PointToPointConstraint

PointToPointConstraint соединяет две точки на разных телах. Локальные якорные точки задаются через pivotA и pivotB. Пример:

const bodyA = new CANNON.Body({ mass: 5 });
const bodyB = new CANNON.Body({ mass: 5 });

const pivotA = new CANNON.Vec3(1, 0, 0); // локальная точка на bodyA
const pivotB = new CANNON.Vec3(0, 1, 0); // локальная точка на bodyB

const constraint = new CANNON.PointToPointConstraint(bodyA, pivotA, bodyB, pivotB, 1e6);
world.addConstraint(constraint);
  • pivotA и pivotB определяют позиции соединения относительно центров масс.
  • Последний параметр 1e6 задаёт силу ограничения, определяющую жёсткость соединения.

Преобразование локальной точки в мировую

Чтобы вычислить глобальные координаты точки на теле, используется матрица трансформации:

const worldPoint = body.pointToWorldFrame(localAnchor);

Этот метод учитывает положение тела (body.position) и ориентацию (body.quaternion), что позволяет корректно интегрировать локальные точки в физический мир.

Обратное преобразование — из мировых координат в локальные:

const localPoint = body.pointToLocalFrame(worldPoint);

Оно необходимо, когда требуется определить положение внешней точки относительно текущего тела.

Якорные точки в HingeConstraint

Для шарнирного соединения HingeConstraint локальные точки определяют место установки оси вращения на каждом теле:

const pivotA = new CANNON.Vec3(0, 1, 0);
const pivotB = new CANNON.Vec3(0, -1, 0);
const axis = new CANNON.Vec3(0, 0, 1); // ось вращения

const hinge = new CANNON.HingeConstraint(bodyA, bodyB, {
    pivotA: pivotA,
    pivotB: pivotB,
    axisA: axis,
    axisB: axis,
});
world.addConstraint(hinge);
  • pivotA и pivotB задают точки крепления на телах.
  • axisA и axisB определяют локальную ось вращения для каждого тела.

Использование локальных координат позволяет сохранить правильное вращение, даже если тела перемещаются или вращаются в пространстве.

Влияние ориентации тела на локальные точки

При изменении body.quaternion локальная точка остаётся зафиксированной относительно тела, а её глобальная позиция изменяется автоматически. Для динамических систем это критично, так как соединения должны корректно следовать за движением и поворотом тела.

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

  • Всегда задавать якорные точки в локальных координатах, если соединение должно «держаться» за тело.
  • Проверять направление осей при создании шарниров — несоответствие локальных осей часто вызывает некорректное вращение.
  • Использовать методы pointToWorldFrame и pointToLocalFrame для отладки и визуализации соединений.
  • Для сложных соединений комбинировать локальные якоря с вычисленными смещениями от центра масс, чтобы оптимизировать стабильность симуляции.

Примеры визуализации локальных точек

Для отладки удобно визуализировать локальные якоря:

const sphereGeom = new THREE.SphereGeometry(0.05, 8, 8);
const sphereMat = new THREE.MeshBasicMaterial({ color: 0xff0000 });

const localAnchorVisual = new THREE.Mesh(sphereGeom, sphereMat);
scene.add(localAnchorVisual);

function updateAnchorVisual() {
    const worldPos = bodyA.pointToWorldFrame(pivotA);
    localAnchorVisual.position.set(worldPos.x, worldPos.y, worldPos.z);
}

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


Этот подход к работе с якорными точками в локальных координатах обеспечивает стабильные физические соединения и упрощает управление сложными объектами в Cannon.js.