Физический пикинг в Cannon.js позволяет взаимодействовать с объектами физического мира с помощью курсора или другого указательного устройства. Основная идея заключается в определении объекта под курсором, создании связи (constraint) между курсором и объектом, и последующем управлении объектом через эту связь.
Cannon.js предоставляет гибкие инструменты для реализации таких
взаимодействий, включая классы Ray, Vec3,
Body, World и различные типы constraints,
например PointToPointConstraint.
Перед реализацией пикинга необходимо создать физический мир и добавить объекты. Ключевые шаги:
const world = new CANNON.World();
world.gravity.set(0, -9.82, 0); // гравитация
// Создание тела для взаимодействия
const sphereBody = new CANNON.Body({
mass: 1,
shape: new CANNON.Sphere(1),
position: new CANNON.Vec3(0, 5, 0)
});
world.addBody(sphereBody);
// Добавление плоской поверхности
const groundBody = new CANNON.Body({
mass: 0,
shape: new CANNON.Plane(),
position: new CANNON.Vec3(0, 0, 0)
});
world.addBody(groundBody);
Ключевой момент — все объекты, которые должны взаимодействовать через
пикинг, должны иметь ненулевую массу. Статические объекты
(mass = 0) участвуют в коллизиях, но не могут
перемещаться.
Для определения объекта под курсором используется луч
(Ray). Он запускается из позиции камеры в направлении
курсора, преобразованного в мировые координаты.
const ray = new CANNON.Ray(world);
ray.from.copy(camera.position);
ray.to.copy(new CANNON.Vec3(x, y, z)); // точка в пространстве, соответствующая курсору
ray.intersectBodies(world.bodies, function(result) {
if(result.length) {
const hitBody = result[0].body;
const hitPoint = result[0].hitPointWorld;
// дальнейшие действия с найденным телом
}
});
Особенности:
from и to — объекты типа
CANNON.Vec3.intersectBodies возвращает массив результатов, каждый
из которых содержит тело, точку попадания и нормаль поверхности.После нахождения тела под курсором создается constraint, фиксирующая
точку на теле относительно курсора. Для этого используется
PointToPointConstraint.
let pickConstraint = null;
const localPivot = new CANNON.Vec3(); // точка на теле относительно его центра
function pickBody(body, hitPoint) {
body.position.vsub(hitPoint, localPivot); // вычисление локальной точки
pickConstraint = new CANNON.PointToPointConstraint(
body,
localPivot,
null, // в пространстве курсора нет тела
hitPoint
);
world.addConstraint(pickConstraint);
}
Ключевые моменты:
localPivot задает смещение относительно центра масс
тела.null указывает, что точка привязки в
мировых координатах, а не к другому телу.При перемещении курсора обновляется позиция точки в мире, к которой
привязано тело. Для этого обновляется pivotB
constraint:
function movePickedBody(hitPointWorld) {
if(pickConstraint) {
pickConstraint.updatePivotB(hitPointWorld);
}
}
Особенности управления:
updatePivotB изменяет мировую позицию привязанной
точки.Когда пользователь отпускает объект, constraint удаляется из мира:
function releasePickedBody() {
if(pickConstraint) {
world.removeConstraint(pickConstraint);
pickConstraint = null;
}
}
Это гарантирует, что тело снова участвует в динамике мира без ограничений.
collisionFilterMask и
collisionFilterGroup.world.step) для корректной
симуляции.Часто пикинг применяется совместно с визуализацией в Three.js. В этом случае луч пересчитывается с учётом камеры и координат мыши на экране:
const mouse = new THREE.Vector2(); // координаты курсора в [-1, 1]
function onMouseMove(event) {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
const vector = new THREE.Vector3(mouse.x, mouse.y, 0.5).unproject(camera);
const dir = vector.sub(camera.position).normalize();
const distance = 100;
const target = camera.position.clone().add(dir.multiplyScalar(distance));
ray.from.copy(camera.position);
ray.to.copy(target);
movePickedBody(ray.to);
}
Интеграция с Three.js позволяет визуально контролировать процесс пикинга, синхронизируя физическое тело и 3D-модель.
Физический пикинг в Cannon.js сочетает лучевое определение объектов, создание constraints и управление через курсор. Правильная настройка массы, фильтрации и плавности движения обеспечивает реалистичное взаимодействие с физическим миром.