关于 r3f-fundamentals
面向 React Three Fiber 开发者的基础技能,涵盖场景结构、渲染循环、类型和资源管理。内容强调根据项目已安装的版本选择 API,并检查渲染与清理行为。
主要功能
- 01场景与 Canvas 结构
- 02Fiber Hooks 和类型边界
- 03渲染循环与按需渲染
- 04渲染器设置注意事项
- 05资源所有权与清理
适用场景
- 01搭建基础 R3F 场景
- 02排查版本相关的 API 用法
- 03实现按需渲染的场景
- 04检查资源释放及组件卸载
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ enzed/ r3f-skills --skill r3f-fundamentals安装后在 Claude Code 中输入/r3f-fundamentals确认已加载。
附带文件references/renderers.md
详细介绍
React Three Fiber 基础知识
选择合适的基准版本
- 选择 API 前,先检查项目的清单文件和锁文件。这些示例针对 Fiber 9 / React 19;Fiber 8 与 React 18 配套。不要仅为匹配示例而升级项目。
- 同时检查已安装的 Three.js 和 Drei 版本。使用与这些版本匹配的已发布文档;如果找不到,请说明不确定之处,不要凭空编造属性。
- 除非任务要求更改,否则保留现有渲染器。对于 WebGPU,请阅读渲染器选择;Fiber 10 alpha API 并非 Fiber 9 API。
最小场景
此示例拥有自己的 Canvas。其父元素的高度必须非零。
import { useRef } from 'react'
import { Canvas, useFrame, type ThreeElements } from '@react-three/fiber'
import type { Mesh } from 'three'
function RotatingBox(props: ThreeElements['mesh']) {
const mesh = useRef<Mesh>(null)
useFrame((_, delta) => {
if (mesh.current) mesh.current.rotation.y += delta * 0.5
})
return (
<mesh {...props} ref={mesh}>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color="coral" />
</mesh>
)
}
export default function Example() {
return (
<Canvas camera={{ position: [0, 0, 5] }} dpr={[1, 2]}>
<ambientLight intensity={0.5} />
<directionalLight position={[3, 4, 5]} intensity={2} />
<RotatingBox />
</Canvas>
)
}
场景和类型边界
- 在 Canvas 下方的组件中调用
useThree、useFrame和加载器 Hook;绝不要在创建该 Canvas 的组件中或事件回调中调用。 - Canvas 的子元素是 Three.js 对象。将 DOM UI 放在 Canvas 外部,或使用 Drei
Html。Canvas 内部的 Suspense 回退也必须遵守相同规则。 - 网格属性使用
ThreeElements['mesh'],引用使用useRef<Mesh>(null)。Fiber 9 对自定义元素使用ThreeElement<typeof Class>;不要使用已移除的Object3DNode或全局JSX.IntrinsicElements扩展。 - 在 Fiber 9 中,
extend(Class)会创建本地类型化组件。只有确实需要共享的小写 JSX 元素时,才使用extend({ Class })并扩展@react-three/fiber模块。 args是构造函数参数:更改它们会重建对象。动画应更新普通属性或引用;如果输入未变,则保留开销较大的形状、数组和材质。- 几何体和材质子元素会自动附加。其他属性请使用显式的
attach,例如对缓冲属性使用attach="attributes-position"。 - Three.js 使用弧度和局部变换。将世界空间输入转换到对象的父级空间后,再赋值给
position。
渲染循环的选择
- 离散的 UI 变化使用 React 状态;逐帧运动则改变自己拥有的引用。重复使用临时向量,并使用以秒为单位的
delta。不要为同一场景创建第二个动画循环。 useThree(state => state.camera)会订阅相机替换,而不是camera.position的变化。在useFrame内读取瞬时值;命令式更改相机投影后,更新投影矩阵。- 默认的
frameloop="always"适用于连续动画。对于可以静止的场景,使用"demand":命令式更改需要调用invalidate(),动画也必须持续触发失效,直到稳定。Drei 控件会自行处理失效。 - 负的帧优先级用于排序更新,不会接管渲染。正的优先级会禁用自动渲染:其所属组件必须负责渲染,并与任何合成器协调。回调按优先级升序运行。
- 不要在 JSX 中重置变换,又由另一个组件为相同的值制作动画。可见性变化不会自动停止回调或释放 GPU 资源。
渲染器与所有权陷阱
- 默认 WebGL Canvas 使用 sRGB 输出和 ACES 胶片式色调映射。
flat会选择NoToneMapping;linear会更改输出色彩空间。两者都不是解决素材褪色问题的通用方法。 - 在 Three.js r182 及更高版本中,使用
shadows="percentage"启用 PCF 阴影。在此基线版本中,Fiber 9 中不带值的shadows会选择已弃用的PCFSoftShadowMap。 - 从默认设置开始;只有确有需求时才添加
preserveDrawingBuffer、提高 DPR 或增加额外渲染通道,并衡量其开销。 - 卸载时,R3F 会释放以声明方式拥有的对象。
<primitive object={...}>不会释放所提供的对象。缓存的加载器素材和共享资源需要明确的所有者;只要还有其他使用者,就不要释放它们。 dispose={null}会让子树不参与自动释放;它不是通用的性能开关。R3F 所有权之外手动分配的资源需要清理。- 效果、订阅和命令式注册必须能经受 Strict Mode 的设置与清理。在添加记忆化之前先进行性能分析;普通的 React 渲染本身不会重启
useFrame动画。
验证
进行类型检查,在浏览器中渲染,检查控制台,调整窗口大小,并卸载后重新挂载。对于按需渲染,请验证它既能唤醒,也能恢复空闲状态。
来源
评论
支持 Markdown