Skip to main content

react-three-fiber

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

Zur Installation springen

Quellinformationen

Repository
recca0120/rubik-cube
Letzte Quellaktivität
14. April 2026 um 20:53
Erkannte Sprache von SKILL.md
Chinesisch
Sterne
1
Forks
0

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
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`。
Auf GitHub ansehen