Partículas
Las partículas son una excelente manera de dar vida a tu escena. Pueden ser utilizadas de diversas formas, tales como nieve, lluvia, fuego, humo o efectos mágicos. A menudo se emplean para crear efectos atmosféricos, como niebla, polvo o chispas.
En esta lección, nos sumergiremos en diferentes maneras de crear partículas utilizando Threejs y React Three Fiber para crear esta escena nocturna nevada con un cielo estrellado y un efecto de caída de nieve:
Ve cómo caen los copos de nieve y cómo las estrellas titilan en el cielo. ❄️✨
Estrellas
Nuestro código inicial contiene esta "Escena de Invierno Low Poly" por EdwiixGG sobre un cubo y una fuente de luz animada.
Se ve bien, pero podemos hacerlo más interesante al agregar estrellas al cielo.
Comencemos agregando estrellas al cielo. La forma más sencilla con React Three Fiber es usar el Stars component de la librería drei.
En components/Experience.jsx
:
// ... import { Stars } from "@react-three/drei"; export const Experience = () => { // ... return ( <> <Stars /> {/* ... */} </> ); };
¡Y voilà, nuestro cielo ahora está lleno de encantadoras estrellas brillantes!
Podemos jugar con sus parámetros como factor
para ajustar el tamaño basado en la distancia o speed
para ajustar el tiempo del efecto de fade.
Consulta la documentación para todos los parámetros disponibles.
Veamos cómo funciona internamente al examinar el código fuente del componente Stars.
Podemos ver que para renderizar las estrellas están usando points llenos de tres atributos en la geometría:
position
: para determinar la posición de cada estrellacolors
: para determinar el color de cada estrellasize
: para determinar el tamaño de cada estrella
Luego, un ShaderMaterial personalizado llamado StarfieldMaterial
es responsable de mostrar correctamente los puntos basados en esos valores de atributos y el uniforme de tiempo para el efecto de desvanecimiento.
En primer lugar, este enfoque es excelente, es ligero y completamente procesado en la GPU, lo que significa que podrías potencialmente colocar un número muy grande de estrellas.
Pero visualmente veo dos aspectos que podrían mejorarse:
- Las estrellas están representadas como cuadrados.
- El efecto de desvanecimiento está sincronizado entre todas las estrellas, resultando en un efecto de parpadeo.
Como no tenemos control sobre esos aspectos con el componente Stars
, ¡vamos a crear nuestro propio sistema de estrellas!
Estrellas Personalizadas
Para tener un control más fácil sobre las estrellas, manejaremos su lógica en el lado de la CPU utilizando instancias.
No te preocupes si no es la forma más optimizada, para un número razonable de estrellas estará bien y será mucho más flexible. Aprenderemos a manejar nuestras partículas en el lado de la GPU cuando construyamos nuestro simple motor de VFX y al aprender TSL más adelante en este capítulo.
PD: La creación de instancias sigue siendo una forma eficiente de renderizar un gran número de objetos con la misma geometría, como se vio en la lección de optimización.
Instancias
Comencemos creando nuestro propio componente StarrySky
en un nuevo archivo components/StarrySky.jsx
:
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} />; };
Estamos creando un InstancedMesh usando una geometría de plano combinada con un material básico de malla.
Gracias al componente <Instance />
de Drei, podemos crear instancias de esta malla y controlar cada partícula (instancia) individualmente.
Ahora eliminemos el componente Stars
con el nuestro personalizado en components/Experience.jsx
:
// ... import { StarrySky } from "./StarrySky"; export const Experience = () => { // ... return ( <> <StarrySky /> {/* ... */} </> ); };
Ahora tenemos este cielo caótico:
¡Es un buen punto de partida!
Ajustemos el tamaño de las estrellas. En el useMemo
responsable de establecer las posiciones de las partículas, podemos agregar un atributo 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), })), [] );
Y en el componente Particle
, podemos pasar este atributo size
al componente Instance
:
const Particle = ({ position, size }) => { const ref = useRef(); return <Instance ref={ref} position={position} scale={size} />; };
Ahora es mejor, tenemos estrellas de diferentes tamaños:
Pero tenemos un problema, las estrellas están posicionadas entre -20
y 20
usando randFloatSpread(20)
, pero queremos que las estrellas estén posicionadas lejos en el cielo.
Para hacer esto, mantengamos el z
siempre en 0
y ajustemos la posición x
para que esté entre 5
y 15
.
Nuestras estrellas estarán posicionadas aleatoriamente entre 5
y 15
en el eje x
.
Y para estar alrededor del centro, rotamos la posición y
entre 0
y 2 * Math.PI
.
El centro nunca contendrá estrellas y las estrellas se dispersarán en todas direcciones.
En el useMemo
responsable de establecer las posiciones de las partículas, podemos ajustar el atributo position
y agregar un atributo 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.