Fuochi d'Artificio
Benvenuti a Sky Adventure, un'azienda futuristica che offre i migliori fuochi d'artificio della galassia! 🎇
Creeremo un sito web 3D per mostrare i nostri fuochi d'artificio utilizzando Three.js, React Three Fiber e il nostro motore VFX.
Questo è quello che costruiremo insieme!
Progetto Iniziale
Il nostro progetto iniziale include già i seguenti elementi:
- Una configurazione base di React Three Fiber con una deliziosa isola fluttuante da cui lanceremo i nostri fuochi d'artificio.
- Effetti di post-processing per far brillare le luci del modello (e successivamente i fuochi d'artificio).
- Una semplice interfaccia utente realizzata con Tailwind CSS con tre pulsanti per lanciare successivamente i fuochi d'artificio.
Ecco cosa otteniamo quando eseguiamo il progetto iniziale.
Fuochi d'Artificio
Per creare i fuochi d'artificio, utilizzeremo il motore VFX che abbiamo costruito nella lezione precedente. Questo motore ci permette di creare e gestire più sistemi di particelle con comportamenti differenti.
useFireworks
Per gestire efficacemente i fuochi d'artificio, creeremo un hook custom chiamato useFireworks
. Questo hook si occuperà della creazione e gestione dei fuochi d'artificio.
Aggiungiamo la libreria zustand al nostro progetto:
yarn add zustand
Ora in una cartella chiamata hooks
, creiamo un nuovo file chiamato useFireworks.js
:
import { create } from "zustand"; const useFireworks = create((set, get) => { return { fireworks: [], }; }); export { useFireworks };
Un semplice store con un array vuoto di fuochi d'artificio.
Aggiungiamo un metodo per creare un fuoco d'artificio:
// ... 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
aggiungerà un nuovo fuoco d'artificio allo store con:
id
: un identificatore unico da usare come chiave nel componente React.position
: dove inizierà il fuoco d'artificio.velocity
: la direzione e la velocità del fuoco d'artificio prima di esplodere.delay
: il tempo prima che il fuoco d'artificio esploda.color
: un array di colori da usare per le particelle dell'esplosione del fuoco d'artificio.
Ora possiamo connettere questo hook alla nostra interfaccia utente per lanciare fuochi d'artificio.
Apri UI.jsx
e connetti il metodo addFirework
ai bottoni:
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> ); };
Per verificare se funziona, creiamo un componente Fireworks.jsx
. Al momento registreremo semplicemente i fuochi d'artificio nella console:
import { useFireworks } from "../hooks/useFireworks"; export const Fireworks = () => { const fireworks = useFireworks((state) => state.fireworks); console.log(fireworks); };
E aggiungiamolo al componente 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> {/* ... */} </> ); };
Importiamo il componente Fireworks
e aggiungiamolo accanto a SkyIsland nel nostro componente <Float />
.
Premendo i bottoni, possiamo vedere nella console che i fuochi d'artificio vengono correttamente aggiunti allo store.
Prima di rappresentarli nella scena, dobbiamo gestire il ciclo di vita dei fuochi d'artificio. Attualmente vengono aggiunti ma mai rimossi.
Nel addFirework
nel nostro hook useFireworks
, possiamo aggiungere un setTimeout
per rimuovere il fuoco d'artificio dopo un certo tempo.
Prima dobbiamo sapere quando viene generato il fuoco d'artificio. Possiamo aggiungere una proprietà time
all'oggetto fuoco d'artificio:
{ id: `${Date.now()}-${randInt(0, 100)}-${state.fireworks.length}`, // ... time: Date.now(), },
Poi chiama setTimeout
per rimuovere i fuochi d'artificio che sono esplosi e svaniti:
addFirework: () => { set((state) => { // ... }); setTimeout(() => { set((state) => ({ fireworks: state.fireworks.filter( (firework) => Date.now() - firework.time < 4000 // Max delay di 2 secondi + Durata massima delle particelle di 2 secondi ), })); }, 4000); },
Filtriamo i fuochi d'artificio che sono stati aggiunti più di 4 secondi fa. In questo modo, manteniamo i fuochi d'artificio che sono ancora attivi.
Regola il tempo in base alle impostazioni finali che utilizzerai per i fuochi d'artificio.
Premendo i bottoni, possiamo vedere nella console che i fuochi d'artificio vengono correttamente rimossi dopo un certo tempo.
Ora possiamo immergerci nella parte che aspettavi: creare i fuochi d'artificio nella scena!
Motore VFX (Wawa VFX)
Per evitare di copiare/incollare il componente dalla lezione precedente, ho pubblicato il motore VFX come pacchetto su npm: Wawa VFX. Puoi installarlo eseguendo:
yarn add wawa-vfx@^1.0.0
Usando
@^1.0.0
, ci assicuriamo di utilizzare sempre la versione principale 1 del pacchetto, ma includendo le ultime versioni minori e patch. In questo modo, possiamo beneficiare delle ultime funzionalità e correzioni di bug senza cambiamenti distruttivi.
Ora possiamo utilizzare i componenti <VFXParticles />
e <VFXEmitter />
nel nostro progetto!
Nell'esperienza, aggiungiamo il componente VFXParticles
alla scena:
// ... 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> </> ); };
Abbiamo aggiunto il componente VFXParticles
con le seguenti impostazioni:
100000
particelle. Visto che quando raggiungiamo il limite, le particelle più vecchie verranno rimosse, dovrebbe essere più che sufficiente per molti fuochi d'artificio contemporaneamente.gravity
per simulare la gravità sulle particelle.-9.8
è la gravità sulla Terra. (Ma aspetta, siamo nello spazio! 👀)renderMode
subillboard
per fronteggiare sempre la telecamera.intensity
a3
per far brillare le particelle nel cielo notturno.
La posizione del componente
<VFXParticles />
non è molto importante. Assicurati solo che sia al livello superiore della scena.
E aggiungiamo un componente VFXEmitter
accanto ai VFXParticles
per modellare l'esplosione in modalità debug
e avere accesso ai controlli visivi:
// ... 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 /> {/* ... */} </> ); };
Assicurati di impostare la prop emitter
con lo stesso name
del componente VFXParticles
e di impostare debug
su true
per vedere i controlli.
Abbozza una prima versione dell'esplosione dei fuochi d'artificio. 💥
Una volta che sei soddisfatto delle impostazioni, puoi rimuovere la prop debug
dal componente VFXEmitter
, premere il pulsante di esportazione e incollare le impostazioni nel componente 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], }} />
Abbiamo tutto pronto per collegare i fuochi d'artificio al motore VFX!
Esplosione di fuochi d'artificio
All'interno del file Fireworks.jsx
, creiamo un componente Firework
che rappresenterà un singolo fuoco d'artificio:
// ... 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> </> ); };
Semplicemente taglia/incolla il VFXEmitter
dal componente Experience
al componente Firework
.
Lo racchiudiamo in un <group />
per poter spostare il fuoco d'artificio nella scena basato sulla position
e velocity
.
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
One-time payment. Lifetime updates included.