Communitygithub.com

phido0410/threejs-3d

使用 Three.js、React Three Fiber (R3F)、Drei 工具庫、Rapier 物理引擎 (@react-three/rapier) 和後處理效果 (@react-three/postprocessing) 建構 3D 場景。適用於網頁或影片中的 3D 場景製作 - 模型 (GLTF)、燈光、攝影機、環境貼圖、物理效果、泛光/暗角/景深效果。若使用 Remotion,另請遵循 remotion-markup/3d.md。

threejs-3d 是什麼?

此技能提供了一套完整且經過驗證的 Three.js 3D 技術棧,涵蓋 React Three Fiber (R3F) 生態系統中的核心套件,包括 Drei 工具庫、Rapier 物理引擎與後處理效果。它同時支援一般的網頁 3D 渲染,以及使用 Remotion 進行程式化影片渲染的特殊情境。對於開發者或 AI 代理來說,此技能具有高度參考價值,因為它不僅提供了標準的場景設置範本,還明確指出了各套件之間的版本相容性(例如 Fiber 9 / Drei 10 / Rapier 2 需要 React 19)。技能文檔深入說明了 `Suspense` 的使用時機、場景縮放的最佳實踐 (`MeshStandardMaterial` 需要光源或環境貼圖),以及 Drei 中各種輔助元件的用途。在物理方面,技能展示了 RigidBody 的碰撞體與類型配置,並解釋了如何手動控制物理步進。後處理部分則說明了 Bloom 效果的作用原理,以及每個效果對渲染效能的成本。最重要的是,技能內容特別針對 Remotion 影片渲染提供了關鍵注意事項,包括:禁止使用 `useFrame`(改用 `useCurrentFrame()`)、移除依賴內部時鐘的動畫輔助元件,以及如何離線烘焙物理模擬結果以符合非序列畫格渲染的需求。這些細節能有效避免初學者常見的錯誤,顯著提升開發效率與最終品質。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/phido0410/claude-video-skills/tree/HEAD/skills/threejs-3d

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

Three.js 3D 技術棧

檢查於 2026-10: three 0.186, @react-three/fiber 9.8, @react-three/drei 10.7, @react-three/rapier 2.2, @react-three/postprocessing 3.2 (+ postprocessing 6.39)。Fiber 9 / Drei 10 / Rapier 2 / postprocessing 3 需要 React 19 (fiber 9.8 的同儕依賴: react >=19 <19.4)。

npm i three @react-three/fiber @react-three/drei
npm i @react-three/rapier                         # 物理引擎
npm i @react-three/postprocessing postprocessing  # 後處理效果
npm i -D @types/three

基礎場景 (網頁)

import { useRef, Suspense } from 'react'
import * as THREE from 'three'
import { Canvas, useFrame } from '@react-three/fiber'
import { OrbitControls, Environment, ContactShadows } from '@react-three/drei'

function Box() {
  const ref = useRef<THREE.Mesh>(null!)
  useFrame((_, delta) => { ref.current.rotation.y += delta }) // 直接改變 refs,切勿在每一影格使用 setState
  return (
    <mesh ref={ref} castShadow>
      <boxGeometry />
      <meshStandardMaterial color="#4a9eff" />
    </mesh>
  )
}

<Canvas camera={{ position: [3, 2, 5], fov: 45 }} dpr={[1, 2]} shadows>
  <ambientLight intensity={0.3} />
  <directionalLight position={[5, 5, 5]} castShadow />
  <Suspense fallback={null}>
    <Box />
    <Environment preset="city" />
  </Suspense>
  <ContactShadows position={[0, -0.5, 0]} opacity={0.5} blur={2} />
  <OrbitControls />
</Canvas>

規則:

  • 任何非同步資源 (useGLTF, useTexture, Environment, Text 字型, Physics WASM) 都需要置於 <Suspense> 之下。
  • 對於首次繪製就會用到的模型,在模組層級使用 useGLTF.preload(url) 進行預載。
  • 場景尺寸保持在 1 到 10 個單位之間;過大或過小的比例會破壞陰影與控制項的運作。
  • MeshStandardMaterial 需要光源或 <Environment>;若兩者皆無,物體會渲染成黑色。

Drei (按需選用)

  • 攝影機/控制: OrbitControls, CameraControls, PerspectiveCamera makeDefault
  • 素材: useGLTF, useTexture, Environment (預設場景: apartment, city, dawn, forest, lobby, night, park, studio, sunset, warehouse), Center, Bounds
  • 場景佈置: ContactShadows, AccumulativeShadows, Stage, Float, Sparkles, Stars, Cloud
  • 材質: MeshTransmissionMaterial (玻璃), MeshReflectorMaterial (反射地板)
  • 文字: Text (SDF, 可使用任何字型網址), Text3D (需要 typeface JSON 格式), Html (DOM 覆蓋層)

Rapier 物理引擎

import { Physics, RigidBody, CuboidCollider, type RapierRigidBody } from '@react-three/rapier'

<Suspense>
  <Physics gravity={[0, -9.81, 0]} /* debug */>
    <RigidBody colliders="hull" restitution={0.6} ref={bodyRef}>
      <mesh><torusGeometry /><meshStandardMaterial /></mesh>
    </RigidBody>
    <RigidBody type="fixed">
      <CuboidCollider args={[10, 0.1, 10]} /> {/* 半邊長 */}
    </RigidBody>
  </Physics>
</Suspense>
// bodyRef.current?.applyImpulse({ x: 0, y: 5, z: 0 }, true)
  • colliders: "cuboid" (預設), "ball", "hull", "trimesh", false (自行添加碰撞體元件)。
  • type: "dynamic" (預設), "fixed", "kinematicPosition", "kinematicVelocity"。
  • timeStep 預設為固定的 1/60。timeStep="vary" 不具確定性。手動步進: useRapier().step(1 / 60)。
  • 在 <Physics> 上啟用 debug 可繪製碰撞體。

後處理效果

import { EffectComposer, Bloom, Vignette, DepthOfField, Noise } from '@react-three/postprocessing'

<EffectComposer>{/* 作為 <Canvas> 的最後一個子元素 */}
  <Bloom luminanceThreshold={0.9} intensity={1.2} mipmapBlur />
  <Vignette offset={0.1} darkness={0.9} />
</EffectComposer>
  • Bloom 只會捕捉亮度高於 luminanceThreshold 的像素。若想讓單一物件發光: 在其材質上設定 emissive 顏色 + emissiveIntensity > 1 + toneMapped={false}。
  • 每個效果都需要一個全螢幕通道;使用 2 到 4 個效果就已足夠。

用於影片

Remotion (請參閱 remotion-markup/3d.md): 使用 @remotion/three 中的 <ThreeCanvas width height>;不使用 useFrame;所有動畫皆來自 useCurrentFrame()。此外:

  • 不要使用 OrbitControls — 透過 frame 來移動攝影機 (使用 interpolate / spring)。
  • 那些依賴自身內部時鐘來進行動畫的 Drei 輔助元件 (Float, Sparkles, Stars, Cloud, MeshWobbleMaterial) 在渲染時會產生閃爍。請將它們移除,或改用 frame 來重現動畫效果。
  • 物理: Remotion 會跨分頁以非順序方式渲染影格,因此即時模擬無法匹配。請將其烘焙: 初始化 @dimforge/rapier3d-compat 一次 (即 @react-three/rapier 底層的引擎),對每一影格執行 world.step() 並設定 timestep = 1 / fps,儲存每個物體在每一影格的位置與旋轉,最後在索引為 frame 時渲染這些變換數值。

在 Remotion 之外 (螢幕錄製、GSAP 驅動): 可以使用 useFrame;但當鏡頭必須可重複時,應透過時間軸 (tl.time()) 來驅動時間,而非使用 delta。

Individual skills in this repo

This repo contains 3 individual skills — each has its own dedicated page.

相關技能