J'ai une scène THREE.js où de nombreux éléments apparaissent et je dois détecter l'objet sur lequel l'utilisateur clique.
Ce que j'ai fait jusqu'à présent est le suivant. La caméra ne bouge pas trop - elle ne change que la position verticale d'une quantité limitée, toujours en regardant vers le même point. Ma méthode approximative est la suivante:
Cette méthode fonctionne approximativement, mais elle est parfois à quelques pixels du point réel.
Existe-t-il une technique plus fiable pour trouver l'objet sur lequel un utilisateur a cliqué?
Cela dépend du type d'appareil photo que vous utilisez.
1) PerspectiveCamera: est un lien ok fourni par Mr.doob .
2) OrthographicCamera: est assez différent:
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);
}
}
Découvrez celui-ci:
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's position is near object's position
}
}
Vérifie l'intersection de la souris et de l'un des cubes dans l'espace 3D et modifie sa couleur. Peut-être que ceci vous aidera.
J'ai rencontré des problèmes en essayant d'implémenter cela pour une toile qui ne prend pas toute la largeur et la hauteur de l'écran. Voici la solution que j'ai trouvée fonctionne assez bien.
Initialisez tout sur une toile existante:
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),
}
Ajoutez un écouteur d'événements au canevas:
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)
Ou pour un événement 'touchstart', changez les lignes calculant mouse.x et mouse.y en:
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;