Hạt Phân
Hạt phân là một cách tuyệt vời để thêm sức sống vào cảnh của bạn. Chúng có thể được sử dụng theo nhiều cách khác nhau, chẳng hạn như tuyết, mưa, lửa, khói hoặc hiệu ứng ma thuật. Chúng thường được sử dụng để tạo hiệu ứng không khí, chẳng hạn như sương mù, bụi hoặc tia lửa.
Trong bài học này, chúng ta sẽ khám phá các cách khác nhau để tạo hạt bằng cách sử dụng Threejs và React Three Fiber để tạo ra cảnh tuyết đêm này với bầu trời đầy sao và hiệu ứng tuyết rơi:
Hãy xem cách mà bông tuyết rơi và các ngôi sao lấp lánh trên bầu trời. ❄️✨
Ngôi sao
Mã khởi động của chúng ta chứa "Cảnh Mùa Đông Low Poly" của EdwiixGG trên một khối lập phương và một nguồn sáng hoạt hình.
Trông đẹp nhưng chúng ta có thể làm cho nó thú vị hơn bằng cách thêm sao vào bầu trời.
Hãy bắt đầu bằng cách thêm sao vào bầu trời. Cách đơn giản nhất với React Three Fiber là sử dụng Stars component từ thư viện drei.
Trong components/Experience.jsx
:
// ... import { Stars } from "@react-three/drei"; export const Experience = () => { // ... return ( <> <Stars /> {/* ... */} </> ); };
Và voilà, bầu trời của chúng ta giờ đã đầy những ngôi sao phát sáng, đẹp tuyệt!
Chúng ta có thể chơi với các tham số của nó như factor
để điều chỉnh kích thước dựa trên khoảng cách hoặc speed
để điều chỉnh thời gian của hiệu ứng fade.
Tham khảo tài liệu để biết tất cả các tham số sẵn có.
Hãy kiểm tra cách nó hoạt động dưới lớp bằng cách duyệt mã nguồn của Stars component.
Chúng ta có thể thấy rằng để render các ngôi sao, họ đang sử dụng points được đổ đầy ba thuộc tính trên hình học:
position
: để xác định vị trí từng ngôi saocolors
: để xác định màu sắc từng ngôi saosize
: để xác định kích thước từng ngôi sao
Sau đó, một ShaderMaterial tùy chỉnh có tên StarfieldMaterial
chịu trách nhiệm hiển thị các điểm dựa vào attributes values và time uniform cho hiệu ứng fade.
Trước hết, cách tiếp cận này rất tuyệt, nó nhẹ và hoàn toàn được xử lý trên GPU có nghĩa là bạn có thể tạo ra một số lượng ngôi sao rất lớn.
Nhưng với mặt hình ảnh, tôi thấy hai điều có thể cải thiện:
- Các ngôi sao được biểu diễn dưới dạng hình vuông.
- Hiệu ứng fade được đồng bộ hóa giữa tất cả các ngôi sao dẫn đến hiệu ứng nhấp nháy.
Vì chúng ta không có khả năng kiểm soát những khía cạnh đó với Stars
component, hãy tạo hệ thống sao riêng của chúng ta!
Ngôi Sao Tuỳ Chỉnh
Để dễ dàng kiểm soát các ngôi sao hơn, chúng ta sẽ quản lý logic của chúng trên phía CPU bằng cách sử dụng instancing.
Đừng lo lắng nếu đây không phải là cách tối ưu nhất, với số lượng ngôi sao hợp lý thì sẽ ổn và linh hoạt hơn nhiều. Chúng ta sẽ học cách xử lý các hạt trên phía GPU khi chúng ta xây dựng VFX engine đơn giản của mình và khi học TSL trong chương này.
PS: Instancing vẫn là một cách hiệu quả để render số lượng lớn các vật thể có cùng hình dạng như đã thấy trong bài học tối ưu hoá.
Instances
Bắt đầu bằng việc tạo component StarrySky
của riêng chúng ta trong file mới 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} />; };
Chúng ta đang tạo một InstancedMesh sử dụng plane geometry kết hợp với mesh basic material.
Nhờ component <Instance />
từ Drei, chúng ta có thể tạo các instance của mesh này và kiểm soát từng hạt (instance) riêng lẻ.
Bây giờ hãy thay thế component Stars
với component tuỳ chỉnh của chúng ta trong components/Experience.jsx
:
// ... import { StarrySky } from "./StarrySky"; export const Experience = () => { // ... return ( <> <StarrySky /> {/* ... */} </> ); };
Bây giờ chúng ta có bầu trời hỗn loạn này:
Đây là một điểm khởi đầu tốt!
Hãy điều chỉnh kích thước của các ngôi sao. Trong useMemo
chịu trách nhiệm đặt vị trí các hạt, chúng ta có thể thêm một thuộc tính 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), })), [] );
Và trong component Particle
, chúng ta có thể truyền thuộc tính size
này cho component Instance
:
const Particle = ({ position, size }) => { const ref = useRef(); return <Instance ref={ref} position={position} scale={size} />; };
Bây giờ thì tốt hơn rồi, chúng ta có các ngôi sao với kích thước khác nhau:
Nhưng chúng ta có một vấn đề, các ngôi sao được đặt giữa -20
và 20
sử dụng randFloatSpread(20)
nhưng chúng ta muốn các ngôi sao được đặt xa hơn trên bầu trời.
Để làm điều này, hãy giữ z
luôn ở 0
và điều chỉnh vị trí x
nằm giữa 5
và 15
.
Các ngôi sao của chúng ta sẽ được đặt ngẫu nhiên giữa 5
và 15
trên trục x
.
Và để ở xung quanh trung tâm chúng ta xoay vị trí y
giữa 0
và 2 * Math.PI
.
Trung tâm sẽ không bao giờ có ngôi sao và các ngôi sao sẽ được phân bố theo mọi hướng.
Trong useMemo
chịu trách nhiệm đặt vị trí các hạt, chúng ta có thể điều chỉnh thuộc tính position
và thêm một thuộc tính 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.