mcpField
T
threejs-r3f

threejs-r3f

github.com/athevon设计与 UI6981.0k 次安装3 周前更新
代码仓库

关于 threejs-r3f

面向 Three.js 和 React Three Fiber 的创意编码技能,提供场景、资源加载、动画与性能优化指导。适合构建 Web 3D 内容的开发者,涵盖 React 与非 React 场景的技术选择。

主要功能

  1. 01Three.js 与 R3F 场景搭建
  2. 02Drei 组件与资源加载
  3. 03动画循环与 Hook 用法
  4. 04模型及纹理优化
  5. 05GPU 资源清理建议

适用场景

  1. 01为 React 项目搭建 3D 场景
  2. 02加载并展示 GLTF 模型
  3. 03优化静态或大型 3D 场景

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/athevon/genjutsu --skill threejs-r3f

安装后在 Claude Code 中输入/threejs-r3f确认已加载。

详细介绍

版本敏感。 以下所有 API 名称、SDK 门槛和浏览器支持声明均已于 2026-09-08 对照一手资料核实。核对了哪些内容以及核对时间,见 _jutsu/VERSIONS.md。如果该日期已久,请在依据版本号采取行动前重新核实。

Three.js 与 React Three Fiber

Web 端 3D。Three.js 是引擎,R3F 是 React 渲染器。 此处提供简明规则。深入内容见 references/。

版本: three r185(0.185.x)· @react-three/fiber 9.x · @react-three/drei 10.x · @react-three/postprocessing 3.x。 R3F 9 仅支持 React 19——其声明的 peer 范围为 react / react-dom >=19 <19.3(drei 10 要求 ^19)。React 18 项目必须继续使用 R3F 8 + drei 9。搭建项目骨架前,请检查已安装的 React 主版本。 渲染器: WebGLRenderer 仍是 R3F 的默认渲染器。WebGPURenderer + TSL 已发布(未标记为实验性),并会在不支持时自动回退到 WebGL 2;但 Three.js 文档称其为“WebGLRenderer 的新替代方案”,而非默认选项。通过异步 gl 回调启用:

import * as THREE from 'three/webgpu'
<Canvas gl={async (props) => { const r = new THREE.WebGPURenderer(props as any); await r.init(); return r }} />

何时使用什么

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

场景搭建模式

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

Hook用途注意事项
useFrame((state, delta) => {})每帧逻辑(动画、物理效果)绝不要在其中调用 setState
useThree()访问 gl、scene、camera、size、viewport、pointer只解构所需内容
useLoader(TextureLoader, url)加载任意 Three.js 资源用 Suspense 包裹父组件
useGraph(scene)从已加载场景中提取节点 / 材质在 useGLTF 后使用很方便
useFrame 提示
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
})

Drei 基础组件

组件用途
EnvironmentHDRI 光照(预设:studio、sunset、city、forest、dawn)
Float静止时的浮动动画(speed、rotationIntensity、floatIntensity)
Text3D挤出式 3D 文本(需要 Facetype.js 的 JSON 字体)
useGLTF加载 .glb/.gltf 模型(返回 { nodes, materials, scene })
useGLTF.preload(url)在组件挂载前预加载模型
MeshTransmissionMaterial玻璃 / 水晶 / 液体折射效果
PresentationControls通过拖动旋转产品展示模型
Center自动将任意网格组居中
DetailedLOD——根据相机距离切换几何体
useTexture加载支持 Suspense 的纹理
Instances以声明式方式实例化重复网格

后期处理

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 默认采用选择性效果——将材质颜色 / emissive 提高到 1.0 以上即可使其发光
  • luminanceThreshold={1} = 除非显式设置 emissive,否则不会有任何内容发光
  • EffectComposer 内部的顺序很重要
  • 效果会合并到单个渲染通道中(这是为了提升性能而设计的)

性能模式

模式适用场景
<Instances> / InstancedMesh100 个以上相同的网格(粒子、树木、群体)
<Detailed distances={[0, 50, 100]}>LOD:根据距离切换高/低精度模型
在 <primitive> 上设置 dispose={null}重用共享几何体时,防止自动释放
useGLTF + Draco压缩 .glb 模型(体积减少 70-90%)
useTexture + KTX2压缩 GPU 纹理(占用 1/4 显存)
在 Canvas 上设置 frameloop="demand"仅在内容发生变化时渲染(静态场景)
使用 useThree 中的 invalidate()在按需模式下触发渲染
<AdaptiveDpr pixelated /> + <AdaptiveEvents />(drei)摄像机移动时降低分辨率并停用射线检测,静止后恢复
<Bvh>(drei)需要快速射线检测/悬停拾取的复杂场景

**目标指标:**绘制调用 < 100,三角形 < 1M,中端 GPU 上达到 60fps。 使用 stats-gl 或 r3f-perf 进行监控。


不要这样做

1. 切勿在 useFrame 中调用 setState

这会导致 React 每秒完整重渲染 60 次。直接修改引用。

// 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
})
2. 切勿在渲染循环中分配内存

每帧调用一次 new Vector3() = GC 峰值 = 卡顿。

// 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)
})
3. 切勿忘记 dispose(内存泄漏)

Three.js 纹理、几何体和材质都存储在 GPU 上。卸载 React 组件不会释放它们。

// 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()
  }
}, [])
4. 切勿让 Canvas 父组件重新渲染

父组件中的状态变化会导致整个 Canvas 卸载并重新挂载 = 闪烁、状态丢失、资源重新加载。

// 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 />
    </>
  )
}
5. 切勿在没有 Suspense 的情况下加载资源

加载器(useGLTF、useTexture、useLoader)会抛出 Promise。没有 Suspense 就会导致崩溃。

// BAD
<Canvas>
  <Model /> {/* useGLTF inside -- will throw */}
</Canvas>

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

快速参考:加载子资源

需求加载
场景样板代码、灯光设置、控件references/scene-setup.md
自定义着色器、GLSL 模式、uniformreferences/shaders.md
动画原理、缓动、时序../motion-principles/SKILL.md
GSAP + Three.js 集成../gsap/SKILL.md

评论

支持 Markdown