Near и far interaction: захват объектов

Babylon.js предоставляет гибкую систему для реализации взаимодействия пользователя с 3D-сценой, включая захват объектов с помощью мыши, касаний или VR/AR контроллеров. Центральными элементами являются Raycasting, Pointer Events, Physics Engine и системы Gizmo.


Raycasting и Picking

Для определения того, на какой объект указывает пользователь, используется метод picking. Основные функции:

  • scene.pick(x, y) — выполняет луч от камеры через экранные координаты (x, y) и возвращает объект типа PickingInfo, содержащий:

    • hit — флаг попадания.
    • pickedMesh — объект, с которым произошло столкновение.
    • pickedPoint — точка столкновения в мировых координатах.
    • ray — объект луча (Ray), использованный для расчёта.

Пример использования для захвата объекта мышью:

canvas.addEventListener("pointerdown", function(evt) {
    let pickResult = scene.pick(evt.clientX, evt.clientY);
    if (pickResult.hit) {
        console.log("Выбран объект:", pickResult.pickedMesh.name);
    }
});

Gizmo: инструмент для захвата и трансформации

Babylon.js предоставляет GizmoManager, который облегчает перемещение, вращение и масштабирование объектов:

const gizmoManager = new BABYLON.GizmoManager(scene);
gizmoManager.positionGizmoEnabled = true; // Включение перемещения
gizmoManager.rotationGizmoEnabled = true; // Включение вращения
gizmoManager.scaleGizmoEnabled = true;    // Включение масштабирования

// Привязка Gizmo к объекту
gizmoManager.attachToMesh(pickResult.pickedMesh);

Особенности:

  • Gizmo автоматически подстраивается под выбранный объект.
  • Можно включать только определённый тип манипуляции.
  • Поддерживает local и world системы координат.

Обработка событий pointer для захвата

Для реализации интерактивного захвата объектов используется цепочка событий:

  1. pointerdown — начало захвата.
  2. pointermove — перемещение объекта.
  3. pointerup — отпускание объекта.

Пример:

let selectedMesh = null;

canvas.addEventListener("pointerdown", function(evt) {
    const pickResult = scene.pick(evt.clientX, evt.clientY);
    if (pickResult.hit) {
        selectedMesh = pickResult.pickedMesh;
    }
});

canvas.addEventListener("pointermove", function(evt) {
    if (selectedMesh) {
        const pickResult = scene.pick(evt.clientX, evt.clientY, mesh => mesh === selectedMesh);
        if (pickResult.hit) {
            selectedMesh.position.copyFrom(pickResult.pickedPoint);
        }
    }
});

canvas.addEventListener("pointerup", function(evt) {
    selectedMesh = null;
});

Важно: для плавного перемещения часто используется Plane или временная фиктивная сетка, на которой фиксируется позиция объекта относительно камеры.


Физический захват объектов

Для реалистичного взаимодействия с объектами можно использовать физический движок Babylon.js:

  • EnablePhysics для сцены.
  • Создание тел (PhysicsImpostor) для объектов.

Пример:

mesh.physicsImpostor = new BABYLON.PhysicsImpostor(
    mesh,
    BABYLON.PhysicsImpostor.BoxImpostor,
    { mass: 1, friction: 0.5, restitution: 0.7 },
    scene
);

// Перемещение с помощью силы или позиции
mesh.physicsImpostor.setLinearVelocity(new BABYLON.Vector3(0, 1, 0));

Использование физики позволяет захватывать объект и перемещать его через реальные столкновения, гравитацию и силы.


VR/AR захват объектов

Babylon.js поддерживает WebXR, что позволяет захватывать объекты в VR и AR с контроллерами:

  • Создание XR Session:
const xrHelper = await scene.createDefaultXRExperienceAsync({});
  • Получение контроллера и навешивание события onSelectStart и onSelectEnd:
xrHelper.input.onControllerAddedObservable.add((controller) => {
    controller.onMotionControllerInitObservable.add((motionController) => {
        motionController.onButtonStateChangedObservable.add(() => {
            if (controller.pointerSelectionMesh) {
                // Привязка к объекту
                gizmoManager.attachToMesh(controller.pointerSelectionMesh);
            }
        });
    });
});

Особенности VR/AR захвата:

  • Контроллеры могут использовать ray-based interaction или прямое grab-based.
  • Для Multi-Hand взаимодействий можно назначить несколько Gizmo на разные контроллеры.

Near и Far Interaction

Near Interaction — взаимодействие с объектом на коротком расстоянии (обычно контакт или хват рукой). Реализуется через:

  • Физические столкновения.
  • Прямое перемещение объекта при соприкосновении.

Far Interaction — взаимодействие с объектом на расстоянии. Используется:

  • Ray-пикинг от курсора или контроллера.
  • Перемещение объектов на основе луча (например, захват через виртуальный “лазер”).

Комбинация этих подходов позволяет создавать гибкие системы манипуляции объектами, где объекты можно “дотянуться рукой” или “подтянуть на расстоянии” через луч.


Оптимизация захвата объектов

  • Ограничение mesh.isPickable для объектов, которые должны быть интерактивными.
  • Использование BoundingInfo для упрощения расчёта пересечения.
  • Для больших сцен — применение Octree или BVH, чтобы ускорить picking.
  • Ограничение перемещений объектами через constraints (например, фиксирование по одной оси).

Рекомендации по реализации

  • Использовать GizmoManager для простых перемещений и вращений.
  • В VR/AR сценах комбинировать ray и прямое физическое взаимодействие.
  • Для физически реалистичных захватов объектов использовать PhysicsImpostor.
  • Всегда учитывать производительность при большом количестве интерактивных объектов через оптимизацию и фильтры picking.

Этот подход обеспечивает гибкость, совместимость с различными устройствами ввода и реалистичное поведение объектов в Babylon.js.