Bonjour !
Dans la leçon précédente, nous avons assemblé notre première scène 3D statique. Vous savez maintenant comment créer des objets en combinant des géométries et des matériaux avec la syntaxe déclarative de React Three Fiber (R3F). C'est une base solide, mais nos créations sont pour l'instant figées dans le temps.
Aujourd'hui, nous allons leur donner vie. L'objectif de cette leçon est d'apprendre à animer des composants en utilisant le hook useFrame, qui est le cœur de toute animation et interactivité dans R3F. Nous verrons comment ce hook nous donne accès à la boucle de rendu pour mettre à jour les propriétés de nos objets à chaque image.
1. Du Statique au Dynamique : La Boucle de Rendu
En développement 3D, l'animation n'est qu'une illusion créée en affichant une série d'images fixes très rapidement (généralement 60 images par seconde). Entre chaque image, nous modifions légèrement les propriétés des objets (position, rotation, etc.). Ce processus continu est géré par une boucle de rendu (ou render loop).
En Three.js "vanilla", on mettrait en place cette boucle manuellement avec une fonction animate() et requestAnimationFrame. R3F simplifie radicalement cela grâce à un hook dédié : useFrame.
useFrame est un hook qui vous permet "d'accrocher" une fonction à la boucle de rendu de R3F. Cette fonction sera exécutée juste avant que chaque nouvelle image ne soit dessinée.
2. Animer un Objet avec useFrame et useRef
Imaginons que nous voulions faire tourner un cube. Comment, depuis notre fonction useFrame, pouvons-nous cibler ce cube en particulier ? La réponse est un autre hook que vous connaissez déjà de React : useRef.
Le processus est simple et se déroule en trois étapes :
- Créer une référence : On initialise une "réf" avec
const meshRef = useRef(). - Attacher la référence : On la lie à notre objet 3D dans le JSX :
<mesh ref={meshRef}>. - Manipuler l'objet : Dans le hook
useFrame, on accède à l'objet Three.js sous-jacent viameshRef.currentet on modifie ses propriétés.
La vidéo suivante explique et démontre ce concept de manière très claire.
React Three Fiber (R3F) - The Basics
Cette section de la vidéo "React Three Fiber (R3F) - The Basics" est le cœur de notre leçon. Elle introduit le hook useFrame pour l'animation, l'utilisation de useRef pour accéder à un objet, et les paramètres state et delta.
Regardez la vidéo de 22:18 à 32:53. Concentrez-vous sur les points suivants : L'introduction du hook useFrame comme un rappel de fonction à chaque image. Comment useRef est utilisé pour obtenir une référence à l'objet <mesh>. La première animation simple : ref.current.rotation.x += delta. Le rôle du paramètre delta pour des animations fluides. L'utilisation du paramètre state (en particulier state.clock.elapsedTime) pour créer des animations basées sur le temps, comme le mouvement de va-et-vient avec Math.sin().
3. Les Clés d'une Bonne Animation
Comme vous l'avez vu dans la vidéo, useFrame n'est pas une simple fonction vide. Elle reçoit deux arguments essentiels : state et delta.
useFrame((state, delta) => { ... })
delta : Pour une vitesse constante
Le paramètre delta contient le temps (en secondes) qui s'est écoulé depuis la dernière image. Pourquoi est-ce si important ?
- Un ordinateur puissant peut afficher 120 images par seconde.
- Un appareil plus modeste peut n'en afficher que 30.
Si vous écrivez meshRef.current.rotation.x += 0.01, votre cube tournera 4 fois plus vite sur l'ordinateur puissant ! En multipliant votre vitesse par delta, vous vous assurez que l'animation a la même vitesse perçue, quel que soit le taux de rafraîchissement.
// Mauvaise pratique : dépendant du framerate
useFrame(() => {
meshRef.current.rotation.x += 0.01;
});
// Bonne pratique : indépendant du framerate
useFrame((state, delta) => {
// Fait tourner le cube de 2 radians par seconde
meshRef.current.rotation.x += 2 * delta;
});
state : La boîte à outils de la scène
L'objet state est une mine d'or d'informations sur l'état actuel de la scène. Il contient, entre autres :
state.camera: La caméra de la scène.state.mouse: Les coordonnées de la souris.state.clock: Une horloge interne à Three.js.
La propriété la plus utile de l'horloge est state.clock.getElapsedTime(). Elle renvoie le nombre total de secondes écoulées depuis le début de l'animation. C'est parfait pour créer des animations cycliques ou non-linéaires, comme un mouvement de balancier ou de rebond.
// Fait "flotter" l'objet de haut en bas
useFrame((state) => {
const elapsedTime = state.clock.getElapsedTime();
meshRef.current.position.y = Math.sin(elapsedTime);
});
Ici, la fonction Math.sin() génère une oscillation douce entre -1 et 1, créant un effet de lévitation naturelle.
L'extrait de vidéo suivant renforce une idée fondamentale pour vous, en tant que développeur React : pourquoi nous utilisons useRef pour modifier l'objet directement au lieu de mettre sa position dans un état React.
React Three Fiber Game Tutorial: Learn React Three Fiber while coding a Crossy Road clone
Dans ce court extrait du "React Three Fiber Game Tutorial", l'auteur explique pourquoi, pour la 3D, il est plus performant de manipuler directement les objets plutôt que de déclencher des re-rendus React.
Regardez de 26:40 à 27:25. L'idée clé est que déclencher un re-rendu React pour chaque frame serait trop lent. R3F nous permet de contourner ce goulot d'étranglement en nous donnant un accès direct à l'objet Three.js via une ref.
4. Atelier : Donnez vie à votre scène
Il est temps de mettre cela en pratique. Nous allons reprendre le code de la leçon précédente (avec la sphère, le cube et le tore) et le rendre dynamique.
-
Créez un composant pour votre cube. Pour garder notre code propre et réutilisable, déplacez le JSX de votre cube dans un nouveau composant
Box.// Dans App.jsx, ou dans un nouveau fichier import { useRef } from 'react'; import { useFrame } from '@react-three/fiber'; function Box(props) { // 1. Créez la référence const meshRef = useRef(); // 3. Utilisez useFrame pour l'animation useFrame((state, delta) => { meshRef.current.rotation.x += delta; meshRef.current.rotation.y += delta * 0.5; }); return ( // 2. Attachez la référence au mesh <mesh {...props} ref={meshRef}> <boxGeometry args={[1, 1, 1]} /> <meshStandardMaterial color="blue" /> </mesh> ); }Notez l'utilisation de
{...props}. Cela nous permet de passer des propriétés commepositiondirectement au composantBox, qui les transmettra au<mesh>. -
Utilisez votre composant
Boxdans la scène principale. Remplacez l'ancien code du cube par votre nouveau composant.// Dans votre composant App function App() { return ( <Canvas> {/* Lumières */} <ambientLight intensity={0.5} /> <directionalLight position={[10, 10, 5]} intensity={1} /> {/* Le cube animé ! */} <Box position={[0, 0, 0]} /> {/* Les autres objets (encore statiques) */} <mesh position={[-2, 0, 0]}> <sphereGeometry args={[0.7, 32, 32]} /> <meshStandardMaterial color="red" /> </mesh> <mesh position={[2, 0, 0]} scale={0.5}> <torusGeometry args={[0.5, 0.2, 32, 100]} /> <meshStandardMaterial color="green" /> </mesh> </Canvas> ); }
Lancez votre application. Votre cube devrait maintenant tourner sur lui-même !
Défi (Bonus) : Créez des composants Sphere et Torus et animez-les différemment. Par exemple, faites "flotter" la sphère avec Math.sin(state.clock.getElapsedTime()).
Conclusion
Vous venez de débloquer la compétence la plus fondamentale pour créer des expériences 3D dynamiques : l'animation. Vous avez transformé une scène statique en un monde vivant.
Points clés à retenir :
- Le hook
useFrameest le moteur de l'animation dans R3F, il exécute une fonction à chaque image. - On utilise
useRefpour obtenir une référence directe à un objet 3D afin de le manipuler dansuseFrame. - Le paramètre
deltaest crucial pour créer des animations dont la vitesse est indépendante du taux de rafraîchissement de l'écran. - L'objet
state, et notammentstate.clock.getElapsedTime(), permet de créer des animations complexes et synchronisées sur le temps.
Aperçu de la prochaine leçon :
Nous avons vu comment utiliser useRef pour modifier les propriétés d'un objet (rotation, position). Dans la prochaine leçon, nous explorerons plus en profondeur ce que useRef nous permet de faire. Vous découvrirez que ref.current n'est pas juste un objet avec des propriétés, mais l'instance complète de l'objet Three.js, avec toutes ses méthodes, ouvrant la porte à des manipulations bien plus avancées.