입자는 장면에 생동감을 더하는 훌륭한 방법입니다. 눈, 비, 불, 연기 또는 마법 효과 등 다양한 방식으로 사용할 수 있습니다. 종종 안개, 먼지 또는 불꽃과 같은 분위기적인 효과를 만드는 데 사용됩니다.
이번 레슨에서는 별이 빛나는 하늘과 눈 내리는 효과가 있는 야경 눈 장면을 만들기 위해 Threejs와 React Three Fiber를 사용하여 입자를 만드는 다양한 방법을 살펴보겠습니다:
눈송이가 떨어지고 별이 하늘에서 반짝이는 모습을 보세요. ❄️✨
별
우리의 스타터 코드에는 큐브 위에 위치한 EdwiixGG의 "Low Poly Winter Scene" 및 애니메이션 조명 소스가 포함되어 있습니다.
멋지지만 하늘에 별을 추가하여 더 흥미롭게 만들 수 있습니다.
먼저 하늘에 별을 추가해 보겠습니다. React Three Fiber에서 가장 간단한 방법은 drei 라이브러리의 Stars 컴포넌트를 사용하는 것입니다.
components/Experience.jsx
에서:
// ... import { Stars } from "@react-three/drei"; export const Experience = () => { // ... return ( <> <Stars /> {/* ... */} </> ); };
그리고 voilà, 우리의 하늘은 이제 반짝이는 아름다운 별들로 가득 찼습니다!
우리는 factor
와 같은 매개변수를 조정하여 거리 기반 크기를 조정하거나 페이드 효과의 타이밍을 조정할 수 있습니다.
사용 가능한 모든 매개변수에 대해서는 문서를 참조하세요.
Stars 컴포넌트의 소스 코드를 살펴보면서 내부적으로 어떻게 작동하는지 확인해 봅시다.
별을 렌더링하기 위해 points를 사용하여 지오메트리에 세 가지 속성을 채우는 것을 볼 수 있습니다:
position
: 각각의 별 위치 결정colors
: 각각의 별 색상 결정size
: 각각의 별 크기 결정
그런 다음 StarfieldMaterial
이라는 커스텀 ShaderMaterial이 이 속성 값과 시간 유니폼을 기반으로 포인트를 올바르게 표시하여 페이드 효과를 담당합니다.
우선, 이 접근 방식은 훌륭하고, 가볍고, 완전히 GPU에서 처리되므로 잠재적으로 매우 많은 수의 별을 구성할 수 있습니다.
그러나 시각적으로 두 가지 개선할 수 있는 점이 보입니다:
- 별은 사각형으로 표현됩니다.
- 모든 별이 동기화된 페이드 효과로 인해 깜박이는 효과가 발생합니다.
Stars
컴포넌트로 이 부분에 대한 제어가 불가능하므로, 우리의 별 시스템을 만들어 봅시다!
Custom Stars
별을 보다 쉽게 제어하기 위해 CPU 측에서 인스턴싱을 사용하여 로직을 처리할 것입니다.
비록 최적화된 방법은 아닐지라도, 적절한 수의 별들을 처리하기에는 문제가 없으며 훨씬 더 유연할 것입니다. 이후 이 장에서 간단한 VFX 엔진을 만들고 TSL을 학습할 때 GPU 측에서 파티클을 처리하는 방법을 배우게 될 것입니다.
참고: 인스턴싱은 같은 지오메트리를 가진 많은 객체를 렌더링하는 효율적인 방법이며, 이는 **최적화 수업**에서 설명되었습니다.
인스턴스
새 파일 components/StarrySky.jsx
에 StarrySky
컴포넌트를 만들어 시작해봅시다:
import { Instance, Instances } from "@react-three/drei"; import { useMemo, useRef } from "react"; import { randFloatSpread } from "three/src/math/MathUtils.js"; export const StarrySky = ({ nbParticles = 1000 }) => { const particles = useMemo( () => Array.from({ length: nbParticles }, (_, idx) => ({ position: [ randFloatSpread(20), randFloatSpread(20), randFloatSpread(20), ], })), [] ); return ( <Instances range={nbParticles} limit={nbParticles} frustumCulled={false}> <planeGeometry args={[1, 1]} /> <meshBasicMaterial /> {particles.map((props, i) => ( <Particle key={i} {...props} /> ))} </Instances> ); }; const Particle = ({ position }) => { const ref = useRef(); return <Instance ref={ref} position={position} />; };
우리는 plane geometry와 mesh basic material을 사용하여 InstancedMesh를 만들고 있습니다.
Drei의 <Instance />
컴포넌트를 통해 이 메쉬의 인스턴스를 만들고 각 파티클(인스턴스)을 개별적으로 제어할 수 있습니다.
이제 components/Experience.jsx
에서 커스텀 컴포넌트로 Stars
컴포넌트를 대체합시다:
// ... import { StarrySky } from "./StarrySky"; export const Experience = () => { // ... return ( <> <StarrySky /> {/* ... */} </> ); };
이제 우리는 다음과 같은 혼란스러운 하늘을 갖게 됩니다:
좋은 출발점입니다!
별의 크기를 조정해 봅시다. 파티클의 위치를 설정하는 useMemo
에서 size
속성을 추가할 수 있습니다:
import { randFloat, randFloatSpread } from "three/src/math/MathUtils.js"; // ... const particles = useMemo( () => Array.from({ length: nbParticles }, (_, idx) => ({ position: [randFloatSpread(20), randFloatSpread(20), randFloatSpread(20)], size: randFloat(0.1, 0.25), })), [] );
그리고 Particle
컴포넌트에서 이 size
속성을 Instance
컴포넌트에 전달할 수 있습니다:
const Particle = ({ position, size }) => { const ref = useRef(); return <Instance ref={ref} position={position} scale={size} />; };
이제 더 나아졌습니다. 우리는 다양한 크기의 별을 가지게 되었습니다:
하지만 문제가 있습니다. 별들은 randFloatSpread(20)
을 사용하여 -20
에서 20
사이에 위치하지만, 우리는 별들이 하늘에서 멀리 위치하길 원합니다.
이를 위해 z
는 항상 0
으로 유지하고 x
위치를 5
에서 15
사이로 조정합니다.
별들은 x
축에서 5
에서 15
사이에 무작위로 위치하게 될 것입니다.
그리고 중심 주위에 모든 별들이 있도록 y
위치를 0
에서 2 * Math.PI
사이로 회전시킵니다.
중심에는 별이 없으며, 별들은 모든 방향으로 퍼지게 됩니다.
파티클의 위치를 설정하는 useMemo
에서 position
속성을 조정하고 rotation
속성을 추가할 수 있습니다:
const particles = useMemo( () => Array.from({ length: nbParticles }, (_, idx) => ({ position: [randFloat(5, 15), randFloatSpread(20), 0], rotation: [0, randFloat(0, Math.PI * 2), 0], size: randFloat(0.1, 0.25), })), [] );
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.