Skip to main content

react-three-fiber

React Three Fiber (R3F) + Three.js + drei 最佳實踐。當需要建立 3D 場景、處理相機/光照、互動事件、動畫、效能優化時使用。

Aller à l'installation

Informations de source

Dépôt
recca0120/rubik-cube
Dernière activité de la source
14 avril 2026 à 20:53
Langue détectée de SKILL.md
chinois
Étoiles
1
Forks
0

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
react-three-fiber
description
React Three Fiber (R3F) + Three.js + drei 最佳實踐。當需要建立 3D 場景、處理相機/光照、互動事件、動畫、效能優化時使用。
# React Three Fiber 最佳實踐 > 基於 2025/5 知識。版本基準:three ^0.170、@react-three/fiber ^9、@react-three/drei ^10。 ## 安裝 ```bash pnpm add three @react-three/fiber @react-three/drei pnpm add -D @types/three ``` ## 基本 Canvas ```tsx import { Canvas } from '@react-three/fiber' import { OrbitControls, Environment } from '@react-three/drei' <Canvas camera={{ position: [5, 5, 5], fov: 50 }} dpr={[1, 2]} shadows> <ambientLight intensity={0.4} /> <directionalLight position={[5, 10, 5]} castShadow /> <mesh> <boxGeometry args={[1, 1, 1]} /> <meshStandardMaterial color="orange" /> </mesh> <OrbitControls /> </Canvas> ``` ## 核心 Hooks ```tsx useFrame((state, delta) => { // 每幀執行,不要 setState!用 ref 直接改 mesh ref.current.rotation.y += delta }) const { camera, gl, scene, size } = useThree() ``` ## drei 常用 - `OrbitControls` / `TrackballControls`:相機控制 - `PerspectiveCamera makeDefault`:自訂主相機 - `Environment preset="city"`:HDR 環境光 - `Bounds`:自動 fit 物件入鏡 - `Html`:3D 裡嵌 DOM( tooltip/label) - `useGLTF('/model.glb')`:載 GLTF,記得 `useGLTF.preload()` - `Instances` / `Instance`:大量重複物件用 instancing ## 互動事件 ```tsx <mesh onPointerDown={(e) => { e.stopPropagation(); /* e.point, e.face, e.object */ }} onPointerOver={(e) => setHover(true)} onPointerMissed={() => setSelected(null)} > ``` 事件會冒泡,要 `stopPropagation()` 阻止穿透。`onPointerMissed` 在點空白處觸發(適合取消選取)。 ## 群組旋轉(魔術方塊關鍵) ```tsx // 把 9 個 cubie 暫時 attach 到一個 Group,旋轉 Group,動畫完再 detach const group = useRef<THREE.Group>(null!) const pivot = useRef<THREE.Object3D>(new THREE.Object3D()) function rotateFace(cubies: THREE.Object3D[], axis: 'x'|'y'|'z', angle: number) { cubies.forEach(c => pivot.current.attach(c)) // useFrame 內 lerp pivot.rotation[axis] 到 angle // 完成後:cubies.forEach(c => scene.attach(c)) 把世界變換烘回各 cubie } ``` 關鍵:`attach()`(非 `add()`)會保留世界座標。 ## 效能陷阱 1. **useFrame 裡 setState**:會觸發 React render,每幀 60 次 → 災難。用 ref 直接操作。 2. **每幀 new 物件**:`new Vector3()` 放元件頂層或 useMemo,不要 useFrame 內建。 3. **同 geometry/material 重複建**:extract 成常數或 useMemo。 4. **shadow 開太多光源**:每個 castShadow 光源一次深度 pass。 5. **dpr 固定 2**:改 `dpr={[1, 2]}` 讓 R3F 自適應。 6. **大 scene 不用 instancing**:>100 重複物件請用 `<Instances>`。 7. **HMR after geometry change**:有時要 key prop 強制 remount。 ## 動畫 - 簡單 lerp:useFrame + `THREE.MathUtils.lerp` - 複雜:`@react-spring/three`(declarative)或 `framer-motion-3d` - Tween:自己 state machine + useFrame ## TypeScript R3F v9 以後 primitive 元素型別在 `@react-three/fiber` 的 `ThreeElements` 已正確。若要擴充自訂元素: ```ts import { extend } from '@react-three/fiber' import { MyMaterial } from './myMaterial' extend({ MyMaterial }) declare module '@react-three/fiber' { interface ThreeElements { myMaterial: ThreeElement<typeof MyMaterial> } } ``` ## 測試策略 R3F 元件難 unit test → 把 **狀態/邏輯** 拆出純函式測(如魔術方塊的 rotate 邏輯),元件只負責渲染。必要時用 `@react-three/test-renderer`。
Voir sur GitHub