关于 threejs-impl-drei
面向 React Three Fiber 开发者的 Drei 实现参考技能,汇总相机控制、环境、阴影、文本、材质和模型加载等组件与 Hooks。也介绍实例化、性能监控及场景布局工具。
主要功能
- 01相机控制与场景布置组件
- 02环境、灯光与阴影工具
- 03文本、HTML 与材质组件
- 04模型、纹理和动画加载 Hooks
- 05实例化与性能辅助工具
适用场景
- 01搭建产品查看器或建筑漫游场景
- 02加载 GLTF 模型并播放动画
- 03在 3D 场景中添加文本或 HUD
- 04优化大量网格和复杂模型的渲染
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ impertio-studio/ three.js-claude-skill-package --skill threejs-impl-drei安装后在 Claude Code 中输入/threejs-impl-drei确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/anti-patterns.mdexamples.mdmethods.md详细介绍
threejs-impl-drei
快速参考
安装
npm install @react-three/drei @react-three/fiber three
关键警告
务必将使用加载器 Hook(useGLTF、useTexture、useFBX、useKTX2、useFont)的组件包裹在 <Suspense fallback={...}> 中。省略 Suspense 会导致整个 React 树崩溃。
务必为主要相机控制组件添加 makeDefault(<OrbitControls makeDefault />)。如果没有 makeDefault,Drei 控制组件就无法接入 R3F 的事件系统,指针事件也会失效。
切勿使用无效的 Environment 预设名称。有效预设仅限:apartment、city、dawn、forest、lobby、night、park、studio、sunset、warehouse。
切勿忘记为关键资源调用 .preload()。在模块作用域中使用 useGLTF.preload('/model.glb'),即可在组件挂载前开始加载。
务必使用 <Instances> 渲染超过 100 个相同网格。每个独立网格都会产生一次绘制调用;实例会将它们批量合并为一次调用。
控制组件
OrbitControls
最常用的相机控制组件。围绕目标进行环绕、缩放和平移。
import { OrbitControls } from '@react-three/drei'
<OrbitControls
makeDefault // ALWAYS add — integrates with R3F events
enableDamping // smooth movement
dampingFactor={0.05}
minDistance={2}
maxDistance={20}
minPolarAngle={0}
maxPolarAngle={Math.PI / 2} // prevent going below ground
/>
其他控制组件
| 组件 | 使用场景 |
|---|---|
CameraControls | 功能全面的相机(适用于复杂场景) |
MapControls | 顶视图地图导航(环绕限制在垂直轴上) |
PresentationControls | 带弹簧物理效果的拖动旋转(产品查看器) |
ScrollControls | 滚动驱动的动画(pages 属性用于设置滚动长度) |
TransformControls | 对选中对象进行平移、旋转和缩放的控件 |
DragControls | 在 3D 空间中拖动对象 |
KeyboardControls | 将键盘输入作为 React 上下文提供 |
FaceControls | 面部追踪相机移动 |
ScrollControls 模式
import { ScrollControls, useScroll } from '@react-three/drei'
<ScrollControls pages={3} damping={0.1}>
<ScrollScene />
</ScrollControls>
function ScrollScene() {
const scroll = useScroll()
useFrame(() => {
const offset = scroll.offset // 0 to 1
})
return <mesh />
}
环境与布景
Environment
加载 HDR 环境贴图,实现逼真的反射和照明。
import { Environment } from '@react-three/drei'
// Preset (downloads from polyhaven CDN)
<Environment preset="city" background blur={0.5} />
// Custom HDR file
<Environment files="/env.hdr" background />
// Custom environment with Lightformers
<Environment background>
<Lightformer form="rect" intensity={2} position={[0, 5, -5]} scale={[10, 5, 1]} />
</Environment>
有效预设: apartment、city、dawn、forest、lobby、night、park、studio、sunset、warehouse。
Stage
在一个组件中完成照明和阴影设置,适用于产品查看器。
import { Stage } from '@react-three/drei'
<Stage preset="rembrandt" intensity={0.5} environment="city" adjustCamera>
<Model />
</Stage>
阴影组件
| 组件 | 使用场景 | 关键属性 |
|---|---|---|
ContactShadows | 柔和的地面阴影(无需灯光) | opacity、scale、blur、far、resolution、color |
AccumulativeShadows | 高质量的烘焙柔和阴影 | frames、alphaTest、scale、opacity |
RandomizedLight | AccumulativeShadows 的子组件 | amount、radius、intensity、position |
BakeShadows | 烘焙阴影贴图后停止更新 | — |
SoftShadows | 用于实时灯光的 PCSS 柔和阴影 | — |
AccumulativeShadows 模式
<AccumulativeShadows temporal frames={100} scale={10} position={[0, -0.5, 0]}>
<RandomizedLight amount={8} radius={4} position={[5, 5, -10]} />
</AccumulativeShadows>
大气效果
| 组件 | 用途 | 关键属性 |
|---|---|---|
Sky | 程序化天空穹顶 | sunPosition、turbidity、rayleigh |
Stars | 粒子星空 | radius、count、factor、fade |
Sparkles | 漂浮粒子 | count、size、speed、color |
Cloud | 体积云 | opacity、speed、segments、bounds |
文本与 HTML
Text(SDF)
通过 troika-three-text 使用有符号距离场渲染的高质量 2D 文本。
import { Text } from '@react-three/drei'
<Text
fontSize={0.5}
color="white"
anchorX="center"
anchorY="middle"
maxWidth={2}
font="/fonts/Inter-Bold.woff"
>
Hello World
</Text>
Text3D
带挤出效果的 3D 几何文本。需要 JSON 字体文件(使用 facetype.js 转换)。
import { Text3D, Center } from '@react-three/drei'
<Center>
<Text3D font="/fonts/Inter_Bold.json" size={0.75} height={0.2} bevelEnabled bevelSize={0.02}>
Hello
<meshStandardMaterial color="orange" />
</Text3D>
</Center>
Html
渲染定位在 3D 空间中的 DOM 元素。
import { Html } from '@react-three/drei'
<mesh position={[0, 2, 0]}>
<Html
transform // transforms with 3D position
distanceFactor={10} // scales with distance
occlude // hides behind 3D objects
center // centers the HTML element
className="label"
>
<div style={{ color: 'white' }}>Annotation</div>
</Html>
</mesh>
Billboard
始终朝向相机。用于标签和精灵。
import { Billboard, Text } from '@react-three/drei'
<Billboard follow={true} lockX={false} lockY={false} lockZ={false}>
<Text fontSize={0.5}>Always Visible</Text>
</Billboard>
Hud
在独立的正交场景中渲染平视显示界面。
import { Hud, OrthographicCamera } from '@react-three/drei'
<Hud renderPriority={1}>
<OrthographicCamera makeDefault position={[0, 0, 5]} />
<Text position={[0, 0, 0]} fontSize={0.1}>HUD Text</Text>
</Hud>
材质
| 组件 | 用途 |
|---|---|
MeshReflectorMaterial | 支持模糊、扭曲和分辨率设置的反射地面 |
MeshTransmissionMaterial | 支持色差、扭曲和厚度设置的玻璃 |
MeshRefractionMaterial | 使用环境立方体贴图实现折射 |
MeshWobbleMaterial | 在 MeshStandardMaterial 上实现动态摇摆效果 |
MeshDistortMaterial | 在 MeshStandardMaterial 上实现 Perlin 噪声扭曲 |
MeshDiscardMaterial | 不渲染任何内容(仅阴影对象) |
shaderMaterial | 用于将自定义 ShaderMaterial 创建为 JSX 的辅助工具 |
MeshReflectorMaterial 示例
<mesh rotation={[-Math.PI / 2, 0, 0]} position={[0, -0.5, 0]}>
<planeGeometry args={[50, 50]} />
<MeshReflectorMaterial
blur={[300, 100]}
resolution={1024}
mixBlur={1}
mixStrength={50}
roughness={1}
depthScale={1.2}
minDepthThreshold={0.4}
maxDepthThreshold={1.4}
color="#151515"
metalness={0.5}
/>
</mesh>
shaderMaterial 辅助工具
import { shaderMaterial } from '@react-three/drei'
import { extend } from '@react-three/fiber'
const WaveMaterial = shaderMaterial(
{ uTime: 0, uColor: new THREE.Color(0.2, 0.0, 0.1) },
/* vertex */ `varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }`,
/* fragment */ `uniform float uTime; uniform vec3 uColor; varying vec2 vUv; void main() { gl_FragColor = vec4(vUv * uColor, 1.0); }`
)
extend({ WaveMaterial })
// Usage: <waveMaterial uTime={clock.elapsedTime} />
加载器
始终将使用加载器的组件包裹在 <Suspense> 中。
| Hook | 返回值 | 预加载 |
|---|---|---|
useGLTF(url) | { nodes, materials, scene, animations } | useGLTF.preload(url) |
useTexture(url) | THREE.Texture 或贴图对象 | useTexture.preload(url) |
useFBX(url) | THREE.Group | useFBX.preload(url) |
useKTX2(url) | 压缩纹理 | useKTX2.preload(url) |
useFont(url) | 用于 Text3D 的字体数据 | useFont.preload(url) |
useAnimations(clips, ref) | { actions, names, mixer, ref } | — |
useVideoTexture(url) | THREE.VideoTexture | — |
useGLTF 用法模式
import { useGLTF } from '@react-three/drei'
function Model(props) {
const { nodes, materials } = useGLTF('/model.glb')
return (
<group {...props}>
<mesh geometry={nodes.Body.geometry} material={materials.Metal} />
</group>
)
}
useGLTF.preload('/model.glb')
useTexture 搭配多个贴图
const textures = useTexture({
map: '/color.jpg',
normalMap: '/normal.jpg',
roughnessMap: '/roughness.jpg',
aoMap: '/ao.jpg',
})
// Spread directly onto material
<meshStandardMaterial {...textures} />
useAnimations 用法模式
function AnimatedModel() {
const group = useRef()
const { nodes, animations } = useGLTF('/character.glb')
const { actions } = useAnimations(animations, group)
useEffect(() => {
actions['Walk']?.play()
return () => actions['Walk']?.stop()
}, [actions])
return <group ref={group}><primitive object={nodes.Scene} /></group>
}
性能
实例
对于大量相同网格(>100),始终使用此功能。可将绘制调用从 N 次减少到 1 次。
import { Instances, Instance } from '@react-three/drei'
<Instances limit={1000} range={1000}>
<boxGeometry />
<meshStandardMaterial />
{positions.map((pos, i) => (
<Instance key={i} position={pos} color="orange" />
))}
</Instances>
合并
将不同几何体合并为一次绘制调用。
import { Merged } from '@react-three/drei'
function Furniture({ nodes }) {
return (
<Merged meshes={[nodes.Chair, nodes.Table, nodes.Lamp]}>
{(Chair, Table, Lamp) => (
<>
<Chair position={[0, 0, 0]} />
<Table position={[2, 0, 0]} />
<Lamp position={[1, 1, 0]} />
</>
)}
</Merged>
)
}
性能辅助工具
| 组件 | 用途 |
|---|---|
Detailed | LOD——根据相机距离切换几何体 |
BakeShadows | 烘焙一次阴影,然后停止更新 |
AdaptiveDpr | 性能下降时降低设备像素比 |
AdaptiveEvents | 性能下降时降低事件触发频率 |
PerformanceMonitor | 监控 FPS,并触发性能回归回调 |
Bvh | 为复杂网格提供 BVH 加速的光线投射 |
meshBounds | 快速包围盒光线投射(替代逐三角形检测) |
PerformanceMonitor 用法模式
<PerformanceMonitor
onIncline={() => setDpr(2)}
onDecline={() => setDpr(1)}
flipflops={3}
onFallback={() => setDpr(0.5)}
/>
布景与布局
| 组件 | 用途 | 关键属性 |
|---|---|---|
Center | 将子项居中到原点 | top、right、bottom、left、front、back |
Float | 悬浮动画 | speed、rotationIntensity、floatIntensity |
Bounds | 根据内容自动调整相机 | fit、clip、observe、margin |
Resize | 将子项规格化为单位大小 | width、height、depth |
抽象与效果
| 组件 | 用途 |
|---|---|
Edges | 渲染线框边缘 |
Outlines | 屏幕空间轮廓 |
Trail | 对象后方的运动轨迹 |
Decal | 将纹理投射到网格表面 |
Splat | 高斯泼溅渲染器 |
Clone | 深度克隆,并共享几何体和材质 |
Image | 带着色器效果的纹理映射平面 |
MeshPortalMaterial | 传送门——在网格表面内渲染场景 |
GradientTexture | 程序化渐变纹理 |
操纵控件
| 组件 | 用途 |
|---|---|
GizmoHelper | 视口方向控件 |
PivotControls | 交互式枢轴操纵控件(平移/旋转/缩放) |
TransformControls | Three.js TransformControls 封装 |
Grid | 可配置的无限网格平面 |
Helper / useHelper | 可视化灯光/相机辅助对象 |
组件选择指南
| 场景 | 组件 |
|---|---|
| 产品查看器 | Stage + OrbitControls + Environment |
| 建筑漫游 | CameraControls + Environment + ContactShadows |
| 滚动体验 | ScrollControls + useScroll |
| 数据可视化 | Instances + Html + Billboard |
| 3D 文本标签 | Text(2D)或 Text3D(挤出)+ Billboard |
| 玻璃/透明物体 | MeshTransmissionMaterial + Environment |
| 反射地板 | MeshReflectorMaterial |
| 大量相同的网格 | Instances(>100)或 Merged(混合几何体) |
| 模型加载 | useGLTF + Suspense + .preload() |
| HUD/叠加层 | Hud 或带有 fullscreen 的 Html |
参考链接
- references/methods.md -- 关键组件属性和 Hook 签名
- references/examples.md -- 完整可运行示例
- references/anti-patterns.md -- 常见错误及修复方法