Feux d'artifice

Starter pack

Bienvenue chez Sky Adventure, une entreprise futuriste fournissant les meilleurs feux d'artifice de la galaxie ! 🎇

Nous allons créer un site web 3D pour présenter nos feux d'artifice en utilisant Three.js, React Three Fiber, et notre moteur VFX.

C'est ce que nous allons construire ensemble !

Projet de démarrage

Notre projet de démarrage inclut déjà les éléments suivants :

  • Une configuration de base React Three Fiber avec une jolie île flottante d'où nous lancerons nos feux d'artifice.
  • Des effets de post-traitement pour rendre lumineux les éclairages du modèle (et plus tard, les feux d'artifice).
  • Une interface simple réalisée avec Tailwind CSS avec trois boutons pour lancer les feux d'artifice par la suite.

Aperçu de Sky Adventure avec l'île flottante

Voici ce que nous obtenons en exécutant le projet de démarrage.

Feux d'artifice

Pour créer les feux d'artifice, nous utiliserons le moteur VFX que nous avons construit dans la leçon précédente. Ce moteur nous permet de créer et de gérer plusieurs systèmes de particules avec des comportements différents.

useFireworks

Pour gérer efficacement les feux d'artifice, nous allons créer un hook personnalisé appelé useFireworks. Ce hook prendra en charge la création et la gestion des feux d'artifice.

Ajoutons la bibliothèque zustand à notre projet :

yarn add zustand

Maintenant, dans un dossier appelé hooks, créez un nouveau fichier nommé useFireworks.js :

import { create } from "zustand";

const useFireworks = create((set, get) => {
  return {
    fireworks: [],
  };
});

export { useFireworks };

Un store simple avec un tableau vide de feux d'artifice.

Ajoutons une méthode pour créer un feu d'artifice :

// ...
import { randFloat, randInt } from "three/src/math/MathUtils.js";

const useFireworks = create((set) => {
  return {
    fireworks: [],
    addFirework: () => {
      set((state) => {
        return {
          fireworks: [
            ...state.fireworks,
            {
              id: `${Date.now()}-${randInt(0, 100)}-${state.fireworks.length}`,
              position: [0, 0, 0],
              velocity: [randFloat(-8, 8), randFloat(5, 10), randFloat(-8, 8)],
              delay: randFloat(0.8, 2),
              color: ["skyblue", "pink"],
            },
          ],
        };
      });
    },
  };
});

// ...

addFirework ajoutera un nouveau feu d'artifice au store avec :

  • id : un identifiant unique à utiliser comme clé dans le composant React.
  • position : où le feu d'artifice commencera.
  • velocity : la direction et la vitesse du feu d'artifice avant l'explosion.
  • delay : le temps avant que le feu d'artifice n'explose.
  • color : un tableau de couleurs à utiliser pour les particules d'explosion du feu d'artifice.

Nous pouvons maintenant connecter ce hook à notre interface utilisateur pour lancer des feux d'artifice.

Ouvrez UI.jsx et connectons la méthode addFirework aux boutons :

import { useFireworks } from "../hooks/useFireworks";

export const UI = () => {
  const addFirework = useFireworks((state) => state.addFirework);

  return (
    <section className="fixed inset-0 z-10 flex items-center justify-center">
      {/* ... */}
      <div
      // ...
      >
        {/* ... */}
        <div className="flex gap-4">
          <button
            // ..
            onClick={addFirework}
          >
            🎆 Classic
          </button>
          <button
            // ..
            onClick={addFirework}
          >
            💖 Love
          </button>
          <button
            // ..
            onClick={addFirework}
          >
            🌊 Sea
          </button>
        </div>
        {/* ... */}
      </div>
    </section>
  );
};

Pour vérifier si cela fonctionne, créons un composant Fireworks.jsx. Nous allons simplement enregistrer les feux d'artifice dans la console pour le moment :

import { useFireworks } from "../hooks/useFireworks";

export const Fireworks = () => {
  const fireworks = useFireworks((state) => state.fireworks);

  console.log(fireworks);
};

Et ajoutons-le au composant Experience :

// ...
import { Fireworks } from "./Fireworks";

export const Experience = () => {
  // ...

  return (
    <>
      {/* ... */}

      <Float
        speed={0.6}
        rotationIntensity={2}
        position-x={4}
        floatIntensity={2}
      >
        <Fireworks />
        <Gltf src="/models/SkyIsland.glb" />
      </Float>

      {/* ... */}
    </>
  );
};

Nous importons le composant Fireworks et l'ajoutons à côté de l'SkyIsland dans notre composant <Float />.

Feux d'artifice dans la console

En appuyant sur les boutons, nous pouvons voir dans la console que les feux d'artifice sont correctement ajoutés au store.

Avant de les représenter dans la scène, nous devons gérer le cycle de vie des feux d'artifice. Actuellement, ils sont ajoutés mais jamais supprimés.

Dans addFirework dans notre hook useFireworks, nous pouvons ajouter un setTimeout pour supprimer le feu d'artifice après un certain temps.

D'abord, nous devons savoir quand le feu d'artifice apparaît. Nous pouvons ajouter une propriété time à l'objet feu d'artifice :

{
  id: `${Date.now()}-${randInt(0, 100)}-${state.fireworks.length}`,
  // ...
  time: Date.now(),
},

Ensuite, nous appelons setTimeout pour supprimer les feux d'artifice qui ont explosé et disparu :

addFirework: () => {
  set((state) => {
    // ...
  });
  setTimeout(() => {
    set((state) => ({
      fireworks: state.fireworks.filter(
        (firework) => Date.now() - firework.time < 4000 // Max delay de 2 secondes + durée de vie max des particules de 2 secondes
      ),
    }));
  }, 4000);
},

Nous filtrons les feux d'artifice qui ont été ajoutés il y a plus de 4 secondes. De cette façon, nous gardons les feux d'artifice qui sont encore actifs.

Ajustez le temps selon les réglages finaux que vous allez utiliser pour les feux d'artifice.

Feux d'artifice dans la console

En appuyant sur les boutons, nous pouvons voir dans la console que les feux d'artifice sont correctement supprimés après un certain temps.

Nous pouvons maintenant plonger dans la partie que vous attendiez : créer les feux d'artifice dans la scène !

Moteur VFX (Wawa VFX)

Pour ne pas copier/coller le composant de la leçon précédente, j'ai publié le moteur VFX en tant que package sur npm : Wawa VFX. Vous pouvez l'installer en exécutant la commande suivante :

yarn add wawa-vfx@^1.0.0

En utilisant @^1.0.0, nous nous assurons d'utiliser toujours la version majeure 1 du package tout en incluant les dernières versions mineures et de correction. De cette façon, nous pouvons bénéficier des dernières fonctionnalités et des corrections de bugs sans changements disruptifs.

Nous pouvons désormais utiliser les composants <VFXParticles /> et <VFXEmitter /> dans notre projet !

Dans l'expérience, ajoutons le composant VFXParticles à la scène :

// ...
import { VFXParticles } from "wawa-vfx";

export const Experience = () => {
  const controls = useRef();

  return (
    <>
      {/* ... */}

      <VFXParticles
        name="firework-particles"
        settings={{
          nbParticles: 100000,
          gravity: [0, -9.8, 0],
          renderMode: "billboard",
          intensity: 3,
        }}
      />

      <EffectComposer>
        <Bloom intensity={1.2} luminanceThreshold={1} mipmapBlur />
      </EffectComposer>
    </>
  );
};

Nous ajoutons le composant VFXParticles avec les paramètres suivants :

  • 100000 particules. Comme lorsque nous atteignons la limite, les particules les plus anciennes seront supprimées, cela devrait être plus que suffisant pour plusieurs feux d'artifice en même temps.
  • gravity pour simuler la gravité sur les particules. -9.8 est la gravité sur Terre. (Mais attendez, nous sommes dans l'espace ! 👀)
  • renderMode sur billboard pour toujours faire face à la caméra.
  • intensity sur 3 pour faire briller les particules dans le ciel nocturne.

L'endroit où vous placez le composant <VFXParticles /> n'est pas très important. Assurez-vous simplement qu'il est au niveau supérieur de la scène.

Et ajoutons un composant VFXEmitter à côté de VFXParticles pour façonner l'explosion en mode debug et avoir accès aux contrôles visuels :

// ...
import { VFXEmitter, VFXParticles } from "wawa-vfx";

export const Experience = () => {
  const controls = useRef();

  return (
    <>
      {/* ... */}

      <VFXParticles
        name="firework-particles"
        settings={{
          nbParticles: 100000,
          gravity: [0, -9.8, 0],
          renderMode: "billboard",
          intensity: 3,
        }}
      />
      <VFXEmitter emitter="firework-particles" debug />

      {/* ... */}
    </>
  );
};

Assurez-vous de définir la prop emitter au même name que le composant VFXParticles et de définir debug sur true pour voir les contrôles.

Élaborez une première version de l'explosion des feux d'artifice. 💥

Une fois que vous êtes satisfait des réglages, vous pouvez supprimer la prop debug du composant VFXEmitter, appuyer sur le bouton d'exportation et coller les paramètres dans le composant VFXEmitter.

<VFXEmitter
  emitter="firework-particles"
  settings={{
    nbParticles: 5000,
    delay: 0,
    spawnMode: "burst",
    colorStart: ["skyblue", "pink"],
    particlesLifetime: [0.1, 2],
    size: [0.01, 0.4],
    startPositionMin: [-0.1, -0.1, -0.1],
    startPositionMax: [0.1, 0.1, 0.1],
    directionMin: [-1, -1, -1],
    directionMax: [1, 1, 1],
    startRotationMin: [degToRad(-90), 0, 0],
    startRotationMax: [degToRad(90), 0, 0],
    rotationSpeedMin: [0, 0, 0],
    rotationSpeedMax: [3, 3, 3],
    speed: [1, 12],
  }}
/>

Nous avons tout ce qu'il faut pour connecter les feux d'artifice au moteur VFX !

Explosion de feux d'artifice

À l'intérieur du fichier Fireworks.jsx, créons un composant Firework qui représentera un feu d'artifice :

// ...
import { useRef } from "react";
import { VFXEmitter } from "wawa-vfx";

export const Fireworks = () => {
  // ...
};

const Firework = ({ velocity, delay, position, color }) => {
  const ref = useRef();
  return (
    <>
      <group ref={ref} position={position}>
        <VFXEmitter
          emitter="firework-particles"
          settings={{
            nbParticles: 5000,
            delay: 0,
            spawnMode: "burst",
            colorStart: ["skyblue", "pink"],
            particlesLifetime: [0.1, 2],
            size: [0.01, 0.4],
            startPositionMin: [-0.1, -0.1, -0.1],
            startPositionMax: [0.1, 0.1, 0.1],
            directionMin: [-1, -1, -1],
            directionMax: [1, 1, 1],
            startRotationMin: [degToRad(-90), 0, 0],
            startRotationMax: [degToRad(90), 0, 0],
            rotationSpeedMin: [0, 0, 0],
            rotationSpeedMax: [3, 3, 3],
            speed: [1, 12],
          }}
        />
      </group>
    </>
  );
};

Il suffit de couper/coller le VFXEmitter du composant Experience au composant Firework.

Nous l'emballons dans un <group /> pour pouvoir déplacer le feu d'artifice dans la scène en fonction de la position et de la velocity.

Three.js logoReact logo

React Three Fiber: The Ultimate Guide to 3D Web Development

✨ You have reached the end of the preview ✨

Go to the next level with Three.js and React Three Fiber!

Get full access to this lesson and the complete course when you enroll:

  • 🔓 Full lesson videos with no limits
  • 💻 Access to the final source code
  • 🎓 Course progress tracking & completion
  • 💬 Invite to our private Discord community
Unlock the Full Course – Just $85

One-time payment. Lifetime updates included.