불꽃놀이
Sky Adventure에 오신 것을 환영합니다. 은하계에서 최고의 불꽃놀이를 제공하는 미래 지향적인 회사입니다! 🎇
우리는 Three.js, React Three Fiber 및 VFX 엔진을 사용하여 불꽃놀이를 선보이는 3D 웹사이트를 만들 것입니다.
이것이 우리가 함께 만들게 될 것입니다!
스타터 프로젝트
우리의 스타터 프로젝트에는 이미 다음이 포함되어 있습니다:
- 불꽃놀이가 발사될 사랑스러운 떠다니는 섬이 있는 기본 React Three Fiber 설정.
- 모델(그리고 나중에 불꽃놀이)에서 빛을 발하게 할 후처리 효과.
- Tailwind CSS로 제작된 간단한 UI와 나중에 불꽃놀이를 발사할 세 개의 버튼.
스타터 프로젝트를 실행할 때 얻을 수 있는 모습입니다.
불꽃놀이
불꽃놀이를 만들기 위해 이전 레슨에서 제작한 VFX 엔진을 사용할 것입니다. 이 엔진은 다양한 동작을 가진 여러 파티클 시스템을 생성하고 관리할 수 있게 해줍니다.
useFireworks
불꽃놀이를 효율적으로 관리하기 위해 useFireworks
라는 커스텀 hook을 만들 것입니다. 이 hook은 불꽃놀이의 생성과 관리를 담당합니다.
zustand 라이브러리를 프로젝트에 추가합시다:
yarn add zustand
이제 hooks
라는 폴더에 useFireworks.js
라는 새 파일을 만듭니다:
import { create } from "zustand"; const useFireworks = create((set, get) => { return { fireworks: [], }; }); export { useFireworks };
불꽃놀이의 빈 배열이 있는 간단한 store입니다.
이제 불꽃놀이를 생성하는 메서드를 추가해봅시다:
// ... 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
는 store에 새 불꽃놀이를 추가합니다:
id
: React 컴포넌트에서 key로 사용할 고유 식별자.position
: 불꽃놀이가 시작할 위치.velocity
: 폭발하기 전 불꽃놀이의 방향과 속도.delay
: 불꽃놀이가 폭발하기 전까지의 시간.color
: 불꽃놀이 폭발 입자에 사용할 색깔 배열.
이제 이 hook을 UI에 연결해 불꽃놀이를 시작할 수 있습니다.
UI.jsx
를 열고 addFirework
메서드를 버튼에 연결합시다:
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> ); };
작동 여부를 확인하기 위해, Fireworks.jsx
컴포넌트를 만들어 보겠습니다. 지금은 콘솔에 불꽃놀이를 단순히 로그로 출력하겠습니다:
import { useFireworks } from "../hooks/useFireworks"; export const Fireworks = () => { const fireworks = useFireworks((state) => state.fireworks); console.log(fireworks); };
그리고 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> {/* ... */} </> ); };
Fireworks
컴포넌트를 가져와 <Float />
컴포넌트 내의 SkyIsland 옆에 추가합니다.
버튼을 누를 때마다, 콘솔에서 불꽃놀이가 store에 올바르게 추가되는 것을 볼 수 있습니다.
장면에서 불꽃놀이를 나타내기 전에 불꽃놀이의 라이프사이클을 관리해야 합니다. 현재로서는 추가되기만 할 뿐 제거되지 않습니다.
useFireworks
hook의 addFirework
에서 일정 시간이 지나면 불꽃놀이를 제거하도록 setTimeout
을 추가할 수 있습니다.
먼저 불꽃놀이가 생성될 때를 알아야 합니다. 불꽃놀이 객체에 time
속성을 추가할 수 있습니다:
{ id: `${Date.now()}-${randInt(0, 100)}-${state.fireworks.length}`, // ... time: Date.now(), },
그런 다음 터지고 사라진 불꽃놀이를 제거하기 위해 setTimeout
을 호출합니다:
addFirework: () => { set((state) => { // ... }); setTimeout(() => { set((state) => ({ fireworks: state.fireworks.filter( (firework) => Date.now() - firework.time < 4000 // 최대 지연 2초 + 최대 파티클 생명 주기 2초 ), })); }, 4000); },
4초 이상 추가된 불꽃놀이는 필터링합니다. 이렇게 하면 여전히 활성화된 불꽃놀이만 유지됩니다.
불꽃놀이의 최종 설정에 따라 시간을 조정하십시오.
버튼을 클릭할 때마다, 콘솔에서 불꽃놀이가 일정 시간이 지나면 올바르게 제거되는 것을 볼 수 있습니다.
이제 여러분이 기다리고 있던 부분: 장면에서 불꽃놀이를 만드는 부분으로 들어가봅시다!
VFX 엔진 (Wawa VFX)
이전 강의의 컴포넌트를 복사/붙여넣기 하지 않기 위해, VFX 엔진을 npm 패키지로 게시했습니다: Wawa VFX. 아래 명령어로 설치할 수 있습니다:
yarn add wawa-vfx@^1.0.0
@^1.0.0
를 사용하면, 패키지의 메이저 버전 1을 항상 사용하되, 최신 마이너 및 패치 버전을 포함합니다. 이렇게 하면, 최신 기능과 버그 수정 사항을 누리면서도 깨지는 변경 사항 없이 사용할 수 있습니다.
이제 프로젝트에서 <VFXParticles />
와 <VFXEmitter />
를 사용할 수 있습니다!
경험적으로, VFXParticles
컴포넌트를 씬에 추가해봅시다:
// ... 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> </> ); };
다음 설정으로 VFXParticles
컴포넌트를 추가합니다:
100000
입자. 한계에 도달하면 가장 오래된 입자가 제거되므로, 동시에 여러 폭죽을 터뜨리기에 충분합니다.gravity
를 설정하여 입자에 중력을 시뮬레이션합니다.-9.8
은 지구의 중력입니다. (하지만 우리는 우주에 있어요! 👀)renderMode
를billboard
로 설정하여 항상 카메라를 바라보게 합니다.intensity
를3
으로 설정하여 밤하늘에서 입자가 빛나게 합니다.
<VFXParticles />
컴포넌트를 어디에 배치하느냐는 크게 중요하지 않습니다. 그냥 씬의 최상위 레벨에 있으면 됩니다.
그리고 VFXEmitter
컴포넌트를 VFXParticles
옆에 추가하여 debug
모드에서 폭발을 형성하고 시각적 제어에 접근해 봅시다:
// ... 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 /> {/* ... */} </> ); };
emitter
속성을 VFXParticles
컴포넌트의 name
과 동일하게 설정하고 debug
를 true
로 설정하여 제어 기능들을 확인하세요.
*첫 번째 버전의 폭죽 폭발을 초안으로 작성하세요. *💥
설정이 만족스럽다면, VFXEmitter
컴포넌트에서 debug
속성을 제거하고, 내보내기 버튼을 누른 후 설정을 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], }} />
이제 폭죽을 VFX 엔진에 연결할 준비가 되었습니다!
불꽃놀이 폭발
Fireworks.jsx
파일 안에서 하나의 불꽃놀이를 나타내는 Firework
컴포넌트를 생성해 봅시다:
// ... 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> </> ); };
VFXEmitter
를 Experience
컴포넌트에서 Firework
컴포넌트로 잘라 붙여 넣으세요.
우리는 <group />
로 감싸서 position
과 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.