Подтвердить что ты не робот

Обнаружить щелкнутый объект в THREE.js

У меня есть сценарий THREE.js, где появляется много элементов, и мне нужно определить, на какой объект нажимает пользователь.

То, что я сделал до сих пор, следующее. Камера не двигается слишком сильно - она ​​только изменяет вертикальное положение на ограниченную величину, всегда глядя в ту же точку. Мой приблизительный метод:

  • Я беру координаты, если клик относительно холста
  • Я переводю их в горизонтальные и вертикальные координаты в сцене webGL с помощью простого масштабирования и добавлю координату Z, которая находится достаточно далеко.
  • Я беру горизонтальный луч, начиная с точки выше, построенной с помощью THREE.Ray()
  • Я использую ray.intersectObjects(), чтобы найти первый элемент вдоль луча.

Этот метод работает приблизительно, но он иногда находится в нескольких пикселах от фактической точки.

Есть ли более надежный метод для поиска объекта, на который щелкнул пользователь?

4b9b3361

Ответ 1

Зависит от того, какую камеру вы используете.

1) PerspectiveCamera: это нормально, что обеспечивает Mr.doob.
2) OrthographicCamera: совсем другое:

var init = function() {
  camera = new THREE.OrthographicCamera( SCREEN_WIDTH / - 2, SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, SCREEN_HEIGHT / - 2, NEAR, FAR);
  document.addEventListener( 'mousedown', onDocumentMouseDown, false );
}

function onDocumentMouseDown( e ) {
  e.preventDefault();
  var mouseVector = new THREE.Vector3();
  mouseVector.x = 2 * (e.clientX / SCREEN_WIDTH) - 1;
  mouseVector.y = 1 - 2 * ( e.clientY / SCREEN_HEIGHT );
  var raycaster = projector.pickingRay( mouseVector.clone(), camera );
  var intersects = raycaster.intersectObject( TARGET );
  for( var i = 0; i < intersects.length; i++ ) {
    var intersection = intersects[ i ],
    obj = intersection.object;
    console.log("Intersected object", obj);
  }
}

Ответ 2

Проверьте это:

var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 5000);
var object; //your object

document.addEventListener('mousedown', onMouseDown, false);

function onMouseDown(e) {
    var vectorMouse = new THREE.Vector3( //vector from camera to mouse
        -(window.innerWidth/2-e.clientX)*2/window.innerWidth,
        (window.innerHeight/2-e.clientY)*2/window.innerHeight,
        -1/Math.tan(22.5*Math.PI/180)); //22.5 is half of camera frustum angle 45 degree
    vectorMouse.applyQuaternion(camera.quaternion);
    vectorMouse.normalize();        

    var vectorObject = new THREE.Vector3(); //vector from camera to object
    vectorObject.set(object.x - camera.position.x,
                     object.y - camera.position.y,
                     object.z - camera.position.z);
    vectorObject.normalize();
    if (vectorMouse.angleTo(vectorObject)*180/Math.PI < 1) {
        //mouse position is near object position

    }
}

Ответ 3

Проверяет пересечение мыши и любого из кубов в 3d-пространстве и изменяет цвет. Возможно, this поможет вам.

Ответ 4

У меня возникли проблемы с попыткой реализовать это для холста, который не занимает всю ширину и высоту экрана. Вот решение, которое я нашел, работает достаточно хорошо.

Инициализировать все на существующем холсте:

var init = function() {
  var canvas_model = document.getElementById('model')
  var viewSize = 50 // Depending on object size, canvas size etc.
  var camera = new THREE.OrthographicCamera(-canvas_model.clientWidth/viewSize, canvas_model.clientWidth/viewSize, canvas_model.clientHeight/viewSize, -canvas_model.clientHeight/viewSize, 0.01, 2000),
}

Добавить прослушиватель событий на холст:

canvas_model.addEventListener('click', function(event){
  var bounds = canvas_model.getBoundingClientRect()
  mouse.x = ( (event.clientX - bounds.left) / canvas_model.clientWidth ) * 2 - 1;
  mouse.y = - ( (event.clientY - bounds.top) / canvas_model.clientHeight ) * 2 + 1;
  raycaster.setFromCamera( mouse, camera );
  var intersects = raycaster.intersectObjects(scene.children, true);
  if (intersects.length > 0) {
     // Do stuff
  }
}, false)

Или для события "touchstart", измените линии, вычисляющие mouse.x и mouse.y, на:

mouse.x = ( (event.touches[0].clientX - bounds.left) / canvas_model.clientWidth ) * 2 - 1;
mouse.y = - ( (event.touches[0].clientY - bounds.top) / canvas_model.clientHeight ) * 2 + 1;