threejs-r3f

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Three.js & React Three Fiber

Three.js & React Three Fiber

3D on the web. Three.js is the engine, R3F is the React renderer. Concise rules here. Deep-dive in
references/
.

网页端3D开发。Three.js是核心引擎,R3F是React渲染器。 此处为简明规则。详细内容请查看
references/
目录。

When to Use What

工具选择指南

NeedToolWhy
Full 3D scene (models, lights, physics)R3F + dreiDeclarative, React-friendly, ecosystem
Vanilla 3D (no React)Three.js directLighter, no React overhead
Simple 3D transforms on UICSS
transform3d
GPU-composited, no WebGL context
2D particles / generativeCanvas 2DSimpler API, less GPU overhead
Shader-only visuals (no scene graph)Raw WebGL / ShaderMaterialMaximum control, minimal abstraction

需求工具原因
完整3D场景(模型、灯光、物理效果)R3F + drei声明式语法、适配React、生态完善
原生3D开发(不使用React)直接使用Three.js更轻量化,无React性能开销
对UI进行简单3D变换CSS
transform3d
GPU合成渲染,无需WebGL上下文
2D粒子/生成式效果Canvas 2DAPI更简单,GPU开销更低
仅着色器视觉效果(无场景图)原生WebGL / ShaderMaterial控制度最高,抽象层最少

Scene Setup Patterns

场景搭建模式

tsx
import { Canvas } from '@react-three/fiber'
import { Environment, OrbitControls } from '@react-three/drei'
import { Suspense } from 'react'

<Canvas camera={{ position: [0, 2, 5], fov: 45 }} dpr={[1, 2]} gl={{ antialias: true }}>
  <Suspense fallback={null}>
    <Environment preset="studio" />
    <OrbitControls makeDefault />
    <Scene />
  </Suspense>
</Canvas>
Rules:
  • Always wrap scene content in
    <Suspense>
    -- loaders (GLTF, textures, HDRI) need it
  • Set
    dpr={[1, 2]}
    to clamp pixel ratio (Retina without melting GPUs)
  • Keep the Canvas parent component minimal -- re-renders propagate into the scene

tsx
import { Canvas } from '@react-three/fiber'
import { Environment, OrbitControls } from '@react-three/drei'
import { Suspense } from 'react'

<Canvas camera={{ position: [0, 2, 5], fov: 45 }} dpr={[1, 2]} gl={{ antialias: true }}>
  <Suspense fallback={null}>
    <Environment preset="studio" />
    <OrbitControls makeDefault />
    <Scene />
  </Suspense>
</Canvas>
规则:
  • 始终用
    <Suspense>
    包裹场景内容——加载器(GLTF、纹理、HDRI)需要它
  • 设置
    dpr={[1, 2]}
    来限制像素比(在Retina屏幕上避免GPU过载)
  • 保持Canvas父组件尽可能简洁——父组件重渲染会传递到场景中

R3F Hooks

R3F钩子函数

HookPurposeGotcha
useFrame((state, delta) => {})
Per-frame logic (animation, physics)Never setState inside
useThree()
Access gl, scene, camera, size, viewport, pointerDestructure only what you need
useLoader(TextureLoader, url)
Load any Three.js resourceWrap parent in Suspense
useGraph(scene)
Extract nodes/materials from loaded sceneUseful after useGLTF
钩子用途注意事项
useFrame((state, delta) => {})
逐帧逻辑处理(动画、物理效果)切勿在内部调用setState
useThree()
访问gl、场景、相机、尺寸、视口、指针仅解构所需内容
useLoader(TextureLoader, url)
加载任意Three.js资源父组件需包裹在Suspense中
useGraph(scene)
从加载的场景中提取节点/材质在useGLTF之后使用更实用

useFrame Tips

useFrame使用技巧

tsx
useFrame((state, delta) => {
  // Use delta for framerate-independent animation
  meshRef.current.rotation.y += delta * 0.5
  // Access clock for time-based effects
  material.uniforms.uTime.value = state.clock.elapsedTime
})

tsx
useFrame((state, delta) => {
  // 使用delta实现帧率无关的动画
  meshRef.current.rotation.y += delta * 0.5
  // 访问clock实现基于时间的特效
  material.uniforms.uTime.value = state.clock.elapsedTime
})

Drei Essentials

Drei核心组件

ComponentUse Case
Environment
HDRI lighting (presets: studio, sunset, city, forest, dawn)
Float
Idle floating animation (speed, rotationIntensity, floatIntensity)
Text3D
Extruded 3D text (needs JSON font from Facetype.js)
useGLTF
Load .glb/.gltf models (returns { nodes, materials, scene })
useGLTF.preload(url)
Preload model before component mounts
MeshTransmissionMaterial
Glass/crystal/liquid refraction effects
PresentationControls
Drag-to-rotate for product showcases
Center
Auto-center any group of meshes
Detailed
LOD -- swap geometry by camera distance
useTexture
Load textures with Suspense support
Instances
Declarative instancing for repeated meshes

组件使用场景
Environment
HDRI光照(预设:工作室、日落、城市、森林、黎明)
Float
闲置漂浮动画(可配置速度、旋转强度、漂浮强度)
Text3D
挤压式3D文字(需要Facetype.js生成的JSON字体)
useGLTF
加载.glb/.gltf模型(返回{ nodes, materials, scene })
useGLTF.preload(url)
在组件挂载前预加载模型
MeshTransmissionMaterial
玻璃/水晶/液体折射效果
PresentationControls
产品展示的拖拽旋转功能
Center
自动居中任意网格组
Detailed
LOD(细节层次)——根据相机距离切换几何体
useTexture
支持Suspense的纹理加载
Instances
重复网格的声明式实例化

Postprocessing

后期处理

tsx
import { EffectComposer, Bloom, ChromaticAberration } from '@react-three/postprocessing'
import { BlendFunction } from 'postprocessing'

<EffectComposer>
  <Bloom
    luminanceThreshold={1}
    luminanceSmoothing={0.4}
    intensity={0.6}
  />
  <ChromaticAberration
    blendFunction={BlendFunction.NORMAL}
    offset={[0.002, 0.002]}
  />
</EffectComposer>
Rules:
  • Bloom is selective by default -- lift material color/emissive above 1.0 to make it glow
  • luminanceThreshold={1}
    = nothing glows unless explicitly emissive
  • Order matters inside EffectComposer
  • Effects are merged into a single pass (performant by design)

tsx
import { EffectComposer, Bloom, ChromaticAberration } from '@react-three/postprocessing'
import { BlendFunction } from 'postprocessing'

<EffectComposer>
  <Bloom
    luminanceThreshold={1}
    luminanceSmoothing={0.4}
    intensity={0.6}
  />
  <ChromaticAberration
    blendFunction={BlendFunction.NORMAL}
    offset={[0.002, 0.002]}
  />
</EffectComposer>
规则:
  • Bloom默认是选择性发光——将材质颜色/自发光值提升至1.0以上即可实现发光效果
  • luminanceThreshold={1}
    = 只有显式设置自发光的对象才会发光
  • EffectComposer内部的组件顺序很重要
  • 特效会合并为单次渲染通道(设计上保证高性能)

Performance Patterns

性能优化方案

PatternWhen
<Instances>
/
InstancedMesh
100+ identical meshes (particles, trees, crowds)
<Detailed distances={[0, 50, 100]}>
LOD: swap hi/lo models by distance
dispose={null}
on
<primitive>
Prevent auto-dispose when reusing shared geometry
useGLTF
+ Draco
Compress .glb models (70-90% size reduction)
useTexture
+ KTX2
Compressed GPU textures (1/4 VRAM)
frameloop="demand"
on Canvas
Only render when something changes (static scenes)
invalidate()
from useThree
Trigger a render in demand mode
Offscreen canvas (
<Canvas eventSource={...}>
)
Run rendering off main thread
Target metrics: < 100 draw calls, < 1M triangles, 60fps on mid-range GPU. Use
stats-gl
or
r3f-perf
to monitor.

方案适用场景
<Instances>
/
InstancedMesh
100个以上相同网格(粒子、树木、人群)
<Detailed distances={[0, 50, 100]}>
LOD:根据距离切换高低精度模型
<primitive>
上设置
dispose={null}
复用共享几何体时防止自动释放
useGLTF
+ Draco
压缩.glb模型(体积减少70-90%)
useTexture
+ KTX2
压缩GPU纹理(显存占用降至1/4)
在Canvas上设置
frameloop="demand"
仅在内容变化时渲染(静态场景)
从useThree调用
invalidate()
在按需模式下触发渲染
离屏画布(
<Canvas eventSource={...}>
在主线程外运行渲染逻辑
目标指标: < 100次绘制调用,< 100万个三角形,中端GPU上达到60fps。使用
stats-gl
r3f-perf
进行监控。

Do Not

禁忌事项

1. Never setState in useFrame

1. 切勿在useFrame中调用setState

Causes full React re-render 60x/second. Mutate refs directly.
tsx
// BAD
useFrame(() => {
  setRotation(prev => prev + 0.01) // React re-render every frame
})

// GOOD
useFrame((_, delta) => {
  meshRef.current.rotation.y += delta * 0.5 // Direct mutation, zero re-renders
})
这会导致React每秒重渲染60次。直接修改ref即可。
tsx
// 错误示例
useFrame(() => {
  setRotation(prev => prev + 0.01) // 每帧触发React重渲染
})

// 正确示例
useFrame((_, delta) => {
  meshRef.current.rotation.y += delta * 0.5 // 直接修改,无重渲染开销
})

2. Never allocate in the render loop

2. 切勿在渲染循环中分配内存

new Vector3()
per frame = GC spikes = stutter.
tsx
// BAD
useFrame((state) => {
  const target = new THREE.Vector3(0, Math.sin(state.clock.elapsedTime), 0)
  meshRef.current.position.copy(target)
})

// GOOD
const _target = useMemo(() => new THREE.Vector3(), [])
useFrame((state) => {
  _target.set(0, Math.sin(state.clock.elapsedTime), 0)
  meshRef.current.position.copy(_target)
})
每帧创建
new Vector3()
会导致GC峰值,造成卡顿。
tsx
// 错误示例
useFrame((state) => {
  const target = new THREE.Vector3(0, Math.sin(state.clock.elapsedTime), 0)
  meshRef.current.position.copy(target)
})

// 正确示例
const _target = useMemo(() => new THREE.Vector3(), [])
useFrame((state) => {
  _target.set(0, Math.sin(state.clock.elapsedTime), 0)
  meshRef.current.position.copy(_target)
})

3. Never forget dispose (memory leak)

3. 切勿忘记释放资源(内存泄漏)

Three.js textures, geometries, and materials live on the GPU. Unmounting a React component does NOT free them.
tsx
// BAD -- texture stays in VRAM after unmount
const texture = useLoader(TextureLoader, '/big-texture.jpg')

// GOOD -- R3F auto-disposes when using JSX primitives
// For manual resources, dispose in cleanup:
useEffect(() => {
  return () => {
    texture.dispose()
    geometry.dispose()
    material.dispose()
  }
}, [])
Three.js的纹理、几何体和材质存储在GPU中。卸载React组件并不会自动释放这些资源。
tsx
// 错误示例 -- 组件卸载后纹理仍占用显存
const texture = useLoader(TextureLoader, '/big-texture.jpg')

// 正确示例 -- 使用JSX原语时R3F会自动释放资源
// 对于手动管理的资源,在清理函数中释放:
useEffect(() => {
  return () => {
    texture.dispose()
    geometry.dispose()
    material.dispose()
  }
}, [])

4. Never re-render the Canvas parent

4. 切勿让Canvas父组件重渲染

State changes in the parent force the entire Canvas to remount = flash, lost state, reloaded assets.
tsx
// BAD
function App() {
  const [uiState, setUiState] = useState(false) // re-renders remount Canvas
  return (
    <>
      <button onClick={() => setUiState(!uiState)}>Toggle</button>
      <Canvas><Scene config={uiState} /></Canvas>
    </>
  )
}

// GOOD -- isolate Canvas in its own component
function App() {
  return (
    <>
      <UI />
      <SceneCanvas />
    </>
  )
}
父组件的状态变化会强制整个Canvas重新挂载,导致画面闪烁、状态丢失、资源重新加载。
tsx
// 错误示例
function App() {
  const [uiState, setUiState] = useState(false) // 重渲染会触发Canvas重新挂载
  return (
    <>
      <button onClick={() => setUiState(!uiState)}>切换</button>
      <Canvas><Scene config={uiState} /></Canvas>
    </>
  )
}

// 正确示例 -- 将Canvas隔离到独立组件中
function App() {
  return (
    <>
      <UI />
      <SceneCanvas />
    </>
  )
}

5. Never load assets without Suspense

5. 切勿在无Suspense的情况下加载资源

Loaders (useGLTF, useTexture, useLoader) throw promises. Without Suspense, you get crashes.
tsx
// BAD
<Canvas>
  <Model /> {/* useGLTF inside -- will throw */}
</Canvas>

// GOOD
<Canvas>
  <Suspense fallback={<Loader />}>
    <Model />
  </Suspense>
</Canvas>

加载器(useGLTF、useTexture、useLoader)会抛出Promise。没有Suspense会导致崩溃。
tsx
// 错误示例
<Canvas>
  <Model /> {/* 内部使用useGLTF -- 会抛出错误 */}
</Canvas>

// 正确示例
<Canvas>
  <Suspense fallback={<Loader />}>
    <Model />
  </Suspense>
</Canvas>

Quick Reference: Loading Sub-resources

快速参考:加载子资源

NeedLoad
Scene boilerplate, lighting rigs, controls
references/scene-setup.md
Custom shaders, GLSL patterns, uniforms
references/shaders.md
Animation principles, easing, timing
../motion-principles/SKILL.md
GSAP + Three.js integration
../gsap/SKILL.md
需求加载路径
场景模板、灯光系统、控制器
references/scene-setup.md
自定义着色器、GLSL模式、uniforms
references/shaders.md
动画原理、缓动、时序
../motion-principles/SKILL.md
GSAP + Three.js集成
../gsap/SKILL.md