T02▸3D002▸three
Particle Field
粒子場
難度 ★★★★★標籤 particles · points · three3 min read
效果簡述
大量小點分布在 3D 空間,緩慢旋轉。Hero 背景、Loading 過場很合適。
用 points + pointsMaterial + bufferAttribute,比每個粒子做 mesh 快百倍。
Claude Code Prompt
參考:3D002 particle field
技術:r3f points + bufferGeometry
具體行為:
- useMemo 生成 Float32Array (count*3) 的位置
- <points><bufferGeometry><bufferAttribute attach="attributes-position" args={[positions, 3]}/></bufferGeometry><pointsMaterial size={0.035} sizeAttenuation/></points>
- useFrame 慢慢旋轉整個 group
限制:
- count 1000 ~ 3000 最佳;超過 5000 移動裝置卡
- pointsMaterial color 用單色(差異化用 size 就好)
- 不要每幀重算 positions(吃 CPU)完整程式碼
'use client'
import { Canvas, useFrame } from '@react-three/fiber'
import { useMemo, useRef } from 'react'
import * as THREE from 'three'
function Particles({ count = 1500 }) {
const ref = useRef<THREE.Points>(null)
const positions = useMemo(() => {
const arr = new Float32Array(count * 3)
for (let i = 0; i < count; i++) {
arr[i*3] = (Math.random() - 0.5) * 8
arr[i*3+1] = (Math.random() - 0.5) * 8
arr[i*3+2] = (Math.random() - 0.5) * 8
}
return arr
}, [count])
useFrame((_, d) => { if (ref.current) ref.current.rotation.y += d * 0.06 })
return (
<points ref={ref}>
<bufferGeometry>
<bufferAttribute attach="attributes-position" args={[positions, 3]} count={count} />
</bufferGeometry>
<pointsMaterial size={0.035} color="#fb923c" sizeAttenuation />
</points>
)
}
export function ParticleField() {
return (
<Canvas camera={{ position: [0,0,5], fov: 55 }} dpr={[1,2]}>
<Particles />
</Canvas>
)
}何時用
- ✅ Hero 背景(科技感)
- ✅ Loading 過場
- ✅ AI / 資料相關產品的視覺隱喻
何時別用
- ❌ 內容區(背景動會分心)
- ❌ 一頁多個粒子場
- ❌ 行動裝置電池敏感場景
我踩過的坑
-
沒 useMemo 每次 render 重算:count 大時整頁 lag。
-
sizeAttenuation false 看起來很假:開了才有「遠的小、近的大」 的透視感。
-
bufferAttribute 第三個參數 itemSize 是 3:xyz。寫成 1 會出怪。
相關效果
- T08 Stars Field — drei 內建版本