Interacciones 3D
El clic en un mundo sin DOM
En HTML normal, hacer clic en un botón es fácil: añades un addEventListener. Pero en Three.js, toda tu escena es un único elemento HTML: el <canvas>. El navegador no tiene ni idea de si has hecho clic en un cubo 3D, una esfera, o en el vacío del espacio.
Raycaster: El francotirador invisible
Para detectar clics u hovers en objetos 3D, usamos un Raycaster. Funciona lanzando un rayo láser invisible matemáticamente exacto desde tu ratón (en la pantalla 2D), atravesando la lente de la cámara hacia las profundidades de la escena 3D.
El Raycaster devolverá una lista de TODOS los objetos que ese láser tocó en su camino, ordenados desde el más cercano hasta el más lejano.
Normalizando coordenadas
Tu ratón se mueve en píxeles (ej. 1920x1080), pero el mundo 3D y WebGL usan un sistema coordinado normalizado donde el centro de la pantalla es [0,0], arriba a la derecha es [1,1] y abajo a la izquierda es [-1,-1]. Deberás convertir la posición de tu ratón a este formato antes de disparar el rayo.
Consejo profesional
El Raycaster es costoso. Si tienes 1000 árboles, no lances el rayo contra todos en cada movimiento del ratón. Mete solo los objetos 'clickeables' en un Array y dile al Raycaster que solo compruebe las colisiones con esos objetos.
Detectando Hover en Objetos 3D
// 1. Instanciamos el Raycaster y un vector para el ratón
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
// Array de cosas interactuables
const objectsToTest = [cubo1, cubo2, esfera];
// 2. Rastreamos el ratón y normalizamos coordenadas
window.addEventListener('mousemove', (event) => {
// Fórmula estándar para convertir a escala -1 a +1
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
});
// 3. En el bucle de animación, disparamos el rayo
function animate() {
requestAnimationFrame(animate);
// Actualizar el rayo desde la cámara y la posición del ratón
raycaster.setFromCamera(mouse, camera);
// Obtener los objetos tocados
const intersects = raycaster.intersectObjects(objectsToTest);
// Restaurar el color de todos primero (pseudo :mouseout)
for(const object of objectsToTest) {
object.material.color.set('#ffffff');
}
// Si tocamos algo, cambiamos su color (pseudo :hover)
if(intersects.length > 0) {
intersects[0].object.material.color.set('#ff0000');
}
renderer.render(scene, camera);
} Pasa el ratón sobre los objetos. El Raycaster detectará la colisión matemáticamente.
Errores comunes
Practica lo aprendido
Dale tacto a tu mundo 3D.