Skip to main content

react-three-fiber

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

Ir para a instalação

Informações da origem

Repositório
recca0120/rubik-cube
Última atividade na origem
14 de abril de 2026 às 20:53
Idioma detectado do SKILL.md
chinês
Estrelas
1
Forks
0

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
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`。
Ver no GitHub