Bonjour ! Dans la leçon précédente, nous avons découvert comment organiser nos objets en hiérarchies à l'aide de THREE.Group. Nous avons vu qu'un objet "enfant" hérite des transformations de son "parent", ce qui simplifie grandement les animations complexes comme les orbites planétaires.
Nous avons terminé en effleurant une idée essentielle : la position d'un objet est relative à son parent. Aujourd'hui, nous allons approfondir ce concept.
Introduction
L'objectif de cette leçon est de vous apprendre à distinguer les coordonnées locales (relatives à un parent) des coordonnées mondiales (relatives à la scène). Comprendre cette distinction est absolument fondamental en 3D. C'est ce qui vous permettra de positionner précisément des objets, de gérer les interactions (comme les clics) et de faire communiquer entre eux des éléments complexes de votre scène.
À la fin de cette leçon, vous saurez non seulement définir ces deux systèmes de coordonnées, mais aussi comment obtenir la position finale d'un objet dans la scène, peu importe sa place dans la hiérarchie.
1. Le Graphe de Scène : La "généalogie" de vos objets
La structure hiérarchique que nous avons créée avec des parents et des enfants s'appelle un graphe de scène (scene graph). C'est un concept central en infographie. Vous pouvez le voir comme l'arbre généalogique de tous les objets de votre scène, où la Scene est l'ancêtre commun.
Votre expérience de développeur web vous a familiarisé avec le DOM, qui est une structure en arbre représentant un document HTML. Un graphe de scène fonctionne sur un principe très similaire :
- La
Sceneest l'équivalent de l'objetdocument. - Les
Groupsont comme des<div>qui servent à organiser et regrouper d'autres éléments. - Les
Mesh(cubes, sphères...) sont comme les éléments finaux (<p>,<img>,<span>).

Cette structure est la clé pour comprendre les deux systèmes de coordonnées qui coexistent dans Three.js.
2. Espace Local vs. Espace Monde
Pour bien comprendre cette dualité, lisons un court extrait d'une ressource que nous avons déjà consultée.
Objets et scène — JavaScript avancé
L'article 'Objets et scène' de David Gayerie contient une explication très claire et concise de la distinction entre l'espace local et l'espace monde. C'est exactement le cœur de notre leçon.
Dans la section 'Hiérarchie d’objets', lisez attentivement le paragraphe qui commence par 'Les transformations appliquées à un objet...' et se termine par '...l’espace de coordonnées du monde (world space).'
Synthétisons et développons ce que vous venez de lire :
L'Espace de Coordonnées Local (Local Space)
- Définition : C'est le système de coordonnées propre à un objet, centré sur son point de pivot. Son origine est toujours
(0, 0, 0)pour lui-même. - En pratique : Quand vous modifiez
monObjet.position,monObjet.rotationoumonObjet.scale, vous travaillez toujours dans l'espace local de cet objet. Vous définissez sa transformation par rapport à son parent direct. - Analogie : Imaginez que vous êtes dans un train en marche. Votre position locale pourrait être "siège 3A, voiture 12". Cette position ne change pas, même si le train (votre "parent") se déplace à grande vitesse.
monCube.position.x = 2signifie "place ce cube à 2 unités sur l'axe X de son parent".
L'Espace de Coordonnées du Monde (World Space)
- Définition : C'est le système de coordonnées global et unique pour toute la scène. Son origine
(0, 0, 0)est le centre de votre univers 3D. - En pratique : La position "monde" d'un objet est sa position finale et absolue dans la scène, calculée par Three.js en combinant la transformation locale de l'objet avec celles de tous ses ancêtres (parent, grand-parent, etc.) jusqu'à la scène.
- Analogie : Pour reprendre l'exemple du train, votre position "monde" serait vos coordonnées GPS exactes sur la planète Terre à un instant T. Cette position change constamment car elle est le résultat de votre position locale dans le train, combinée à la position du train qui se déplace dans le monde.
3. Exercice : Observer la différence en pratique
Rien de tel qu'un exemple concret pour solidifier cette idée. Nous allons construire une "voiture" très simple et observer en temps réel les coordonnées locales et mondiales d'une de ses roues.
-
Mise en place : Repartez d'un projet Three.js de base (scène, caméra, renderer,
OrbitControls). -
Créer la voiture :
- Créez un
THREE.Groupqui représentera la voiture. Ce sera notre objet parent. - Créez un
Mesh(unBoxGeometry) pour le châssis et ajoutez-le au groupe. - Créez un autre
Mesh(unCylinderGeometry) pour une roue. - Positionnez la roue dans son espace local par rapport au groupe. Par exemple :
roue.position.set(1, -0.5, 1.5);. - Ajoutez la roue au groupe de la voiture.
- Enfin, ajoutez le groupe de la voiture à la scène.
- Créez un
-
Animer et Observer :
- Dans votre boucle d'animation, faites avancer la voiture en modifiant la position du groupe :
voitureGroupe.position.z -= 0.05;. - À chaque image, nous allons récupérer et afficher deux valeurs :
- La position locale de la roue :
roue.position. - La position monde de la roue : nous utiliserons la méthode
roue.getWorldPosition().
- La position locale de la roue :
- Dans votre boucle d'animation, faites avancer la voiture en modifiant la position du groupe :
Voici le code pour vous guider. Portez une attention particulière aux commentaires.
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
// ----- Initialisation standard -----
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(4, 5, 8);
camera.lookAt(0, 0, 0);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const controls = new OrbitControls(camera, renderer.domElement);
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
// ----- Création de la voiture (hiérarchie) -----
// 1. Le groupe parent pour la voiture
const voitureGroupe = new THREE.Group();
scene.add(voitureGroupe);
// 2. Le châssis (un simple cube)
const chassisGeometrie = new THREE.BoxGeometry(2, 1, 4);
const chassisMateriau = new THREE.MeshBasicMaterial({ color: 0xcccccc });
const chassis = new THREE.Mesh(chassisGeometrie, chassisMateriau);
voitureGroupe.add(chassis); // Ajouté au groupe
// 3. La roue avant-droite (un cylindre)
const roueGeometrie = new THREE.CylinderGeometry(0.4, 0.4, 0.2, 16);
roueGeometrie.rotateX(Math.PI / 2); // Orienter la roue correctement
const roueMateriau = new THREE.MeshBasicMaterial({ color: 0x333333 });
const roueAvantDroite = new THREE.Mesh(roueGeometrie, roueMateriau);
// 4. On définit la position LOCALE de la roue par rapport à la voiture
roueAvantDroite.position.set(1.1, -0.5, 1.5);
voitureGroupe.add(roueAvantDroite);
// ----- Variable pour stocker la position monde -----
// On la déclare ici pour ne pas la recréer à chaque image (bonne pratique)
const positionMondeRoue = new THREE.Vector3();
// ----- Boucle d'animation -----
function animate() {
requestAnimationFrame(animate);
// 5. On anime le parent : le groupe de la voiture
voitureGroupe.position.z -= 0.02;
// Réinitialiser la position si la voiture sort de l'écran
if (voitureGroupe.position.z < -10) {
voitureGroupe.position.z = 10;
}
// 6. On récupère la position MONDE de la roue
roueAvantDroite.getWorldPosition(positionMondeRoue);
// 7. On observe les valeurs dans la console
console.clear(); // Pour ne pas inonder la console
console.log("Position LOCALE roue :", roueAvantDroite.position);
console.log("Position MONDE roue :", positionMondeRoue);
controls.update();
renderer.render(scene, camera);
}
animate();
Lancez ce code et ouvrez la console de votre navigateur. Vous observerez que :
- La valeur de
Position LOCALEreste fixe :(1.1, -0.5, 1.5). C'est normal, la roue ne bouge pas par rapport au châssis. - La valeur de
Position MONDEchange en permanence, spécifiquement sa coordonnée Z, car la voiture (le parent) avance dans la scène (le monde).
Pourquoi est-ce si important ?
Maîtriser cette distinction est crucial pour de nombreuses tâches avancées :
- Détection de clics (Raycasting) : Lorsque vous cliquez sur un objet, Three.js vous donne le point d'intersection en coordonnées monde. Si vous voulez savoir quelle partie d'un modèle complexe a été cliquée, vous devrez peut-être convertir ce point en coordonnées locales par rapport au modèle.
- Suivi de caméra : Pour qu'une caméra suive un personnage, vous aurez besoin de la position monde du personnage à chaque image pour positionner la caméra correctement.
- Interactions entre objets : Pour savoir si votre voiture est arrivée sur une ligne d'arrivée, vous devrez comparer leurs positions dans le même référentiel : l'espace monde.
Conclusion
Aujourd'hui, nous avons mis des noms et des concepts précis sur un comportement que nous avions déjà observé. Cette formalisation est une étape clé de votre apprentissage.
Points clés à retenir :
- Les objets d'une scène Three.js forment une hiérarchie appelée graphe de scène.
- L'espace local est le référentiel d'un objet par rapport à son parent. Les propriétés
.position,.rotationet.scalesont toujours définies dans cet espace. - L'espace monde est le référentiel global de la scène. C'est la transformation finale d'un objet après application de toutes les transformations de ses ancêtres.
- La méthode
monObjet.getWorldPosition(unVecteur)permet de récupérer la position d'un objet dans l'espace monde.
Aperçu de la prochaine leçon :
Maintenant que nous savons obtenir la position de n'importe quel objet dans le monde, nous pouvons commencer à effectuer des calculs avec ces positions. La prochaine leçon portera sur le calcul de la distance et de la direction entre deux points dans l'espace. C'est la brique suivante pour créer des scènes véritablement interactives.