Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 35

Animer avec useFrame

Recommended resources

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 :

  1. Créer une référence : On initialise une "réf" avec const meshRef = useRef().
  2. Attacher la référence : On la lie à notre objet 3D dans le JSX : <mesh ref={meshRef}>.
  3. Manipuler l'objet : Dans le hook useFrame, on accède à l'objet Three.js sous-jacent via meshRef.current et 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.

  1. 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 comme position directement au composant Box, qui les transmettra au <mesh>.

  2. Utilisez votre composant Box dans 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 useFrame est le moteur de l'animation dans R3F, il exécute une fonction à chaque image.
  • On utilise useRef pour obtenir une référence directe à un objet 3D afin de le manipuler dans useFrame.
  • Le paramètre delta est crucial pour créer des animations dont la vitesse est indépendante du taux de rafraîchissement de l'écran.
  • L'objet state, et notamment state.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.