Bonjour ! Dans la leçon précédente, nous avons appris à manipuler la position, l'échelle et la direction de nos objets avec la classe Vector3. Nous avons terminé en posant une question : comment gérer des objets complexes composés de plusieurs parties, comme une voiture dont les roues doivent bouger avec la carrosserie ?
Introduction
La réponse à cette question est au cœur de l'organisation de toute scène 3D complexe. Essayer de calculer manuellement la position de chaque roue par rapport à la voiture à chaque image serait non seulement fastidieux, mais aussi très sujet aux erreurs.
L'objectif de cette leçon est de vous apprendre à organiser des objets en hiérarchies logiques à l'aide de THREE.Group. Cette technique fondamentale vous permettra de traiter un ensemble d'objets comme une seule entité, simplifiant radicalement les transformations et les animations. C'est le principe qui permet d'animer un bras de robot, un système solaire ou un personnage.
À la fin de cette leçon, vous serez capable de construire des scènes complexes et articulées en imbriquant des objets les uns dans les autres de manière logique.
1. Le principe de la hiérarchie parent-enfant
Dans Three.js, tout objet qui peut être placé dans une scène (comme un Mesh, une Light ou une Camera) hérite d'une classe de base appelée Object3D. Une propriété essentielle de Object3D est qu'il peut avoir des "enfants".
Le concept est simple :
- Vous pouvez ajouter un
Object3D(l'enfant) à un autreObject3D(le parent) en utilisant la méthodeparent.add(enfant). - Dès lors, toute transformation (position, rotation, échelle) appliquée au parent est également appliquée à tous ses enfants.
Les transformations de l'enfant s'ajoutent à celles héritées du parent. Par exemple, si un parent est déplacé de 5 unités vers la droite, et que son enfant est déplacé de 2 unités vers le haut, la position finale de l'enfant sera de 5 unités à droite ET de 2 unités vers le haut par rapport à l'origine du parent.
Pour mieux visualiser cette structure, imaginez un arbre généalogique où la Scene est l'ancêtre commun.

2. THREE.Group : Le conteneur universel
Plutôt que d'utiliser un Mesh visible comme parent, Three.js fournit un objet spécialement conçu pour cela : THREE.Group. C'est un conteneur invisible dont le seul but est de regrouper d'autres objets. Son centre (0,0,0) sert de "pivot" pour toutes les transformations appliquées au groupe.
La mécanique est très simple :
- On crée un nouveau groupe :
const monGroupe = new THREE.Group(); - On y ajoute des objets :
monGroupe.add(monCube); monGroupe.add(maSphere); - On ajoute le groupe à la scène :
scene.add(monGroupe);
Désormais, si vous faites monGroupe.rotation.y += 0.01;, le cube et la sphère tourneront ensemble autour du centre du groupe.
La vidéo suivante montre très clairement cette mise en pratique.
Particules 3D connectées avec Three.js
Cette vidéo de Grafikart.fr, bien que sur un autre sujet, contient une excellente démonstration de la création et de l'animation d'un Group. Observez comment le groupe est créé, comment les objets y sont ajoutés, et comment la rotation du groupe affecte tout son contenu.
Regardez la première partie (de 00:34:31 à 00:35:06) pour voir la création du groupe. Ensuite, regardez la seconde partie (de 00:35:06 à 00:37:08) pour voir comment l'animation est appliquée au groupe entier.
3. Construire des hiérarchies complexes : l'exemple du système solaire
La véritable puissance des groupes apparaît lorsque vous les imbriquez (nesting). C'est ainsi que l'on crée des articulations complexes. Un exemple classique est un système solaire : la Lune tourne autour de la Terre, et l'ensemble (Terre + Lune) tourne autour du Soleil.
Tenter de faire cela sans hiérarchie est un véritable casse-tête mathématique.
Three.js Groups Tutorial | How to Organize Code with Three.js Groups
La vidéo suivante (en anglais) illustre parfaitement ce problème et sa solution. La clarté des visuels et du code la rend très facile à comprendre, même sans maîtriser l'anglais.
Regardez d'abord la partie de 01:19 à 02:27. Elle montre la complexité de l'animation d'une orbite avec des calculs manuels (Math.sin, Math.cos). Ensuite, regardez de 02:27 à 05:06. L'auteur réorganise le code en utilisant des groupes imbriqués : un earthOrbit qui contient la Terre, et un moonOrbit (lui-même enfant de earthOrbit) qui contient la Lune. Observez comme l'animation devient simple : il suffit de faire tourner les groupes pivots.
Cette approche hiérarchique est la solution standard pour ce type de problème. L'article ci-dessous détaille une implémentation complète en français pour un système Terre-Lune, en utilisant exactement cette logique de groupes imbriqués.
Animer le système Terre-Lune en HTML et JavaScript (2/2)
Cet article de 'La voie du dev' explique en détail la logique de hiérarchie pour animer le système Terre-Lune. Il est un excellent complément à la vidéo précédente.
Lisez les sections 'Solution : hiérarchie d’objets' et l'arborescence qui la suit. Cela formalise l'idée que vous venez de voir en vidéo : décomposer un mouvement complexe en une série de transformations parent-enfant simples.
4. Introduction aux coordonnées locales vs. mondiales
Cette idée de hiérarchie introduit un concept fondamental que nous détaillerons dans la prochaine leçon. Lorsque vous définissez monCube.position.x = 2;, cette position est relative au parent du cube. C'est son espace de coordonnées local.
La position finale du cube dans la scène, après application de toutes les transformations de ses parents, est sa position dans l'espace de coordonnées du monde (world space).
Objets et scène — JavaScript avancé
Lisez cette courte explication pour bien comprendre la distinction entre l'espace local et l'espace du monde.
Lisez uniquement le premier paragraphe de la section 'Hiérarchie d’objets', qui commence par 'Les transformations appliquées à un objet...' jusqu'à '...l’espace de coordonnées du monde (world space).'
Retenez simplement pour l'instant : .position, .rotation et .scale opèrent toujours dans l'espace local de l'objet.
Exercice pratique
Mettons en pratique la création d'une hiérarchie simple. Nous allons créer un "soleil" et une "planète" qui orbite autour.
-
Mise en place : Repartez de votre code de base (scène, caméra, renderer, boucle d'animation,
OrbitControls). -
Créez le soleil :
- Créez une sphère (
SphereGeometry) de rayon 1. - Utilisez un
MeshBasicMaterialde couleur jaune (0xffff00). - Créez le
Meshdu soleil et ajoutez-le directement à la scène.
- Créez une sphère (
-
Créez le groupe pour l'orbite :
- Créez un
THREE.GroupnomméplanetOrbitGroup. - Ajoutez ce groupe à la scène. Il sera notre pivot invisible.
- Créez un
-
Créez la planète :
- Créez une autre sphère, plus petite (rayon 0.3).
- Utilisez un
MeshBasicMaterialde couleur bleue (0x0095dd). - Créez le
Meshde la planète. - Positionnez la planète à 4 unités du centre sur l'axe X :
planet.position.x = 4;. - Important : Ajoutez la planète non pas à la scène, mais au
planetOrbitGroup.
-
Animez l'orbite :
- Dans votre boucle d'animation
animate(), mettez à jour la rotation du groupe pivot :planetOrbitGroup.rotation.y += 0.005;.
- Dans votre boucle d'animation
Si tout est correct, vous devriez voir la planète bleue tourner autour du soleil jaune central. Vous pouvez toujours utiliser OrbitControls pour vous déplacer dans la scène et observer le mouvement sous différents angles.
Solution
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
// Scène, Caméra, Renderer
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 10;
camera.position.y = 5;
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
// AxesHelper pour le débogage
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
// 1. Créer le soleil
const sunGeometry = new THREE.SphereGeometry(1, 32, 32);
const sunMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 });
const sun = new THREE.Mesh(sunGeometry, sunMaterial);
scene.add(sun); // Ajouté directement à la scène
// 2. Créer le groupe pour l'orbite
const planetOrbitGroup = new THREE.Group();
scene.add(planetOrbitGroup); // Le groupe est ajouté à la scène
// 3. Créer la planète
const planetGeometry = new THREE.SphereGeometry(0.3, 32, 32);
const planetMaterial = new THREE.MeshBasicMaterial({ color: 0x0095dd });
const planet = new THREE.Mesh(planetGeometry, planetMaterial);
// 4. Positionner la planète et l'ajouter au groupe
planet.position.x = 4;
planetOrbitGroup.add(planet); // La planète est enfant du groupe
// Boucle d'animation
function animate() {
requestAnimationFrame(animate);
// 5. Animer l'orbite en faisant tourner le groupe
planetOrbitGroup.rotation.y += 0.005;
// Bonus : la planète tourne aussi sur elle-même
planet.rotation.y += 0.01;
controls.update();
renderer.render(scene, camera);
}
animate();
Conclusion
Félicitations ! Vous venez de maîtriser l'un des concepts les plus importants pour la création de scènes 3D structurées.
Points clés à retenir :
- Les objets 3D peuvent être organisés en hiérarchies parent-enfant.
- Les enfants héritent des transformations (position, rotation, échelle) de leurs parents.
THREE.Groupest un conteneur invisible idéal pour servir de parent ou de pivot.- L'imbrication de groupes permet de créer des animations complexes (comme des orbites) de manière simple et intuitive.
- Les transformations que nous appliquons (
.position,.rotation) se font dans l'espace de coordonnées local de l'objet (relatif à son parent).
Aperçu de la prochaine leçon :
Nous avons effleuré la différence entre les coordonnées locales et mondiales. Dans la prochaine leçon, nous allons explorer ce sujet en profondeur. Vous apprendrez comment déterminer la position exacte d'un objet dans la scène, peu importe sa profondeur dans la hiérarchie, et comment passer d'un système de coordonnées à l'autre. C'est une compétence essentielle pour des interactions avancées, comme faire en sorte qu'un objet suive la caméra.