Drag-and-drop (перетаскивание) объектов в 3D-пространстве с использованием Three.js требует понимания нескольких ключевых компонентов: Raycaster, обработка событий мыши и преобразование координат экран → мир.
Raycaster используется для определения пересечения курсора с объектами сцены. С его помощью можно вычислить, какой объект пользователь пытается выбрать и перемещать.
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
События мыши (mousedown, mousemove,
mouseup) позволяют отслеживать начало, процесс и завершение
перетаскивания:
mousedown – определяет объект для захвата.mousemove – изменяет позицию объекта в
пространстве.mouseup – завершает операцию drag-and-drop.Для корректной работы требуется преобразовать координаты курсора из пикселей экрана в нормализованные координаты устройства (NDC):
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
После этого Raycaster может вычислить пересечение с объектами сцены:
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(scene.children, true);
if (intersects.length > 0) {
selectedObject = intersects[0].object;
}
Для удобного перетаскивания часто создается виртуальная плоскость
(THREE.Plane) через объект и камеру. Это позволяет объекту
перемещаться только по определенной поверхности, избегая смещения в
глубину сцены:
const plane = new THREE.Plane();
const planeNormal = new THREE.Vector3();
При захвате объекта вычисляется нормаль плоскости относительно камеры:
planeNormal.copy(camera.position).sub(selectedObject.position).normalize();
plane.setFromNormalAndCoplanarPoint(planeNormal, selectedObject.position);
Для обновления позиции объекта при движении мыши используется пересечение с плоскостью:
const intersection = new THREE.Vector3();
raycaster.ray.intersectPlane(plane, intersection);
selectedObject.position.copy(intersection).add(offset);
Где offset — вектор смещения от точки клика до центра
объекта.
Для сцен с большим количеством объектов важно фильтровать объекты для перетаскивания. Используется массив интерактивных объектов:
const draggableObjects = [];
И при пересечении проверяется только этот массив:
const intersects = raycaster.intersectObjects(draggableObjects, true);
Чтобы перемещение выглядело плавным, используют интерполяцию:
selectedObject.position.lerp(intersection.clone().add(offset), 0.2);
Здесь 0.2 — коэффициент сглаживания, который можно
регулировать для ускорения или замедления движения.
Three.js позволяет накладывать ограничения на движение объекта:
x, y или z).Пример ограничения по оси X:
selectedObject.position.x = intersection.x;
Когда используется THREE.OrbitControls, необходимо временно отключать вращение камеры во время перетаскивания:
controls.enabled = !isDragging;
Где isDragging — булева переменная, активная при захвате
объекта.
requestAnimationFrame для плавного
обновления сцены.Эта схема позволяет создавать интерактивные 3D-сцены с естественным и контролируемым перемещением объектов, полностью используя возможности Three.js и современных браузеров.