Suivre la souris
Transformer la position du pointeur en coordonnées de -1 à 1, puis s’en servir pour déplacer un objet dans la scène.
import * as THREE from "three";
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
45,
window.innerWidth / window.innerHeight,
0.1,
100,
);
camera.position.z = 5;
const renderer = new THREE.WebGLRenderer({
antialias: true,
});
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const cube = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshNormalMaterial(),
);
scene.add(cube);
const mouse = {
x: 0,
y: 0,
};
window.addEventListener("pointermove", (event) => {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = (event.clientY / window.innerHeight) * 2 - 1;
console.log(mouse);
});
renderer.setAnimationLoop((time) => {
cube.position.x = mouse.x * 2;
cube.position.y = -mouse.y * 2;
cube.rotation.x = time / 1000;
cube.rotation.y = time / 1500;
renderer.render(scene, camera);
});
window.addEventListener("resize", () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
Le principe
On part de la doc « Première scène » : même scène, même caméra, même cube. On ajoute deux choses :
- un écouteur
pointermovequi range la position du pointeur dans un objetmouse; - dans la boucle d’animation, une ligne qui place le cube selon
mouse.
pointermove marche à la souris, au stylet et au doigt : c’est le bon réflexe plutôt que mousemove.
Ramener la position entre -1 et 1
event.clientX donne la position du pointeur en pixels, depuis le bord gauche. Ce nombre dépend de la taille de l’écran : on le ramène entre -1 (bord gauche) et 1 (bord droit), pour que le même code marche partout.
const mouse = {
x: 0,
y: 0,
};
window.addEventListener("pointermove", (event) => {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = (event.clientY / window.innerHeight) * 2 - 1;
console.log(mouse);
});Un exemple sur un écran de 1000 pixels de large, pointeur à 750 pixels :
750 / 1000donne0.75: la position entre 0 et 1 ;0.75 * 2donne1.5: entre 0 et 2 ;1.5 - 1donne0.5: entre -1 et 1.
Le console.log affiche les valeurs à chaque mouvement : ouvre la console pour vérifier qu’elles restent bien entre -1 et 1, puis supprime-le.
Déplacer le cube
renderer.setAnimationLoop((time) => {
cube.position.x = mouse.x * 2;
cube.position.y = -mouse.y * 2;
cube.rotation.x = time / 1000;
cube.rotation.y = time / 1500;
renderer.render(scene, camera);
});Le * 2 choisit l’amplitude : le cube va de -2 à 2 unités. Le signe moins sur y compte : à l’écran, clientY grandit vers le bas, alors que dans la scène 3D l’axe y monte. Sans lui, le cube part à l’envers.
On lit mouse dans la boucle d’animation, pas dans l’écouteur : l’écouteur se contente de noter la position, la boucle décide quoi en faire à chaque image.
Pour aller plus loin
Pour un mouvement plus doux, le cube peut rattraper le pointeur petit à petit au lieu de sauter dessus. À chaque image, il parcourt 10 % de la distance qui lui reste :
cube.position.x += (mouse.x * 2 - cube.position.x) * 0.1;
cube.position.y += (-mouse.y * 2 - cube.position.y) * 0.1;Essaie aussi de faire tourner la caméra plutôt que le cube, ou de changer la couleur du fond selon mouse.x.