r3f-fundamentals
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseReact Three Fiber Fundamentals
React Three Fiber 基础
Declarative Three.js via React components. R3F maps Three.js objects to JSX elements with automatic disposal, reactive updates, and React lifecycle integration.
通过React组件实现声明式Three.js。R3F将Three.js对象映射为JSX元素,具备自动资源释放、响应式更新及React生命周期集成特性。
Quick Start
快速开始
tsx
import { Canvas } from '@react-three/fiber';
function App() {
return (
<Canvas>
<ambientLight intensity={0.5} />
<pointLight position={[10, 10, 10]} />
<mesh>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color="hotpink" />
</mesh>
</Canvas>
);
}tsx
import { Canvas } from '@react-three/fiber';
function App() {
return (
<Canvas>
<ambientLight intensity={0.5} />
<pointLight position={[10, 10, 10]} />
<mesh>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color="hotpink" />
</mesh>
</Canvas>
);
}Core Principle: Declarative Scene Graph
核心原则:声明式场景图
R3F converts Three.js imperative API to React's declarative model:
| Three.js (Imperative) | R3F (Declarative) |
|---|---|
| |
| |
| JSX nesting handles hierarchy |
| Automatic on unmount |
R3F将Three.js命令式API转换为React的声明式模型:
| Three.js(命令式) | R3F(声明式) |
|---|---|
| |
| |
| JSX嵌套处理层级关系 |
| 卸载时自动执行 |
Canvas Configuration
Canvas配置
tsx
import { Canvas } from '@react-three/fiber';
<Canvas
// Renderer settings
gl={{ antialias: true, alpha: false, powerPreference: 'high-performance' }}
dpr={[1, 2]} // Device pixel ratio range
shadows // Enable shadow maps
// Camera (default: PerspectiveCamera)
camera={{
fov: 75,
near: 0.1,
far: 1000,
position: [0, 0, 5]
}}
// Or use orthographic
orthographic
camera={{ zoom: 50, position: [0, 0, 100] }}
// Performance
frameloop="demand" // 'always' | 'demand' | 'never'
performance={{ min: 0.5 }} // Adaptive performance
// Events
onCreated={({ gl, scene, camera }) => {
// Access Three.js objects after mount
}}
// Sizing
style={{ width: '100vw', height: '100vh' }}
/>tsx
import { Canvas } from '@react-three/fiber';
<Canvas
// 渲染器设置
gl={{ antialias: true, alpha: false, powerPreference: 'high-performance' }}
dpr={[1, 2]} // 设备像素比范围
shadows // 启用阴影贴图
// 相机(默认:透视相机)
camera={{
fov: 75,
near: 0.1,
far: 1000,
position: [0, 0, 5]
}}
// 或使用正交相机
orthographic
camera={{ zoom: 50, position: [0, 0, 100] }}
// 性能设置
frameloop="demand" // 'always' | 'demand' | 'never'
performance={{ min: 0.5 }} // 自适应性能
// 事件
onCreated={({ gl, scene, camera }) => {
// 挂载后访问Three.js对象
}}
// 尺寸设置
style={{ width: '100vw', height: '100vh' }}
/>Frameloop Modes
渲染循环模式
| Mode | When to Use |
|---|---|
| Continuous animation (games, simulations) |
| Static scenes, only re-render on state change |
| Manual control via |
tsx
// Demand mode with manual invalidation
import { useThree } from '@react-three/fiber';
function Controls() {
const invalidate = useThree(state => state.invalidate);
const handleDrag = () => {
// Update state...
invalidate(); // Request re-render
};
}| 模式 | 使用场景 |
|---|---|
| 持续动画(游戏、模拟场景) |
| 静态场景,仅在状态变化时重新渲染 |
| 通过 |
tsx
// 手动触发重渲染的demand模式
import { useThree } from '@react-three/fiber';
function Controls() {
const invalidate = useThree(state => state.invalidate);
const handleDrag = () => {
// 更新状态...
invalidate(); // 请求重渲染
};
}Scene Hierarchy
场景层级
JSX nesting = Three.js parent-child relationships:
tsx
<group position={[0, 2, 0]} rotation={[0, Math.PI / 4, 0]}>
{/* Children inherit parent transforms */}
<mesh position={[1, 0, 0]}>
<sphereGeometry args={[0.5, 32, 32]} />
<meshStandardMaterial color="blue" />
</mesh>
<mesh position={[-1, 0, 0]}>
<boxGeometry args={[0.8, 0.8, 0.8]} />
<meshStandardMaterial color="red" />
</mesh>
</group>JSX嵌套对应Three.js父子关系:
tsx
<group position={[0, 2, 0]} rotation={[0, Math.PI / 4, 0]}>
{/* 子元素继承父元素变换属性 */}
<mesh position={[1, 0, 0]}>
<sphereGeometry args={[0.5, 32, 32]} />
<meshStandardMaterial color="blue" />
</mesh>
<mesh position={[-1, 0, 0]}>
<boxGeometry args={[0.8, 0.8, 0.8]} />
<meshStandardMaterial color="red" />
</mesh>
</group>Common Container Components
常用容器组件
tsx
// Group: Transform container (no rendering)
<group position={[0, 0, 0]} />
// Object3D: Base class, rarely used directly
<object3D />
// Scene: Usually implicit (Canvas creates one)
<scene />tsx
// Group:变换容器(无渲染内容)
<group position={[0, 0, 0]} />
// Object3D:基类,很少直接使用
<object3D />
// Scene:通常隐式创建(Canvas会自动生成)
<scene />Camera Systems
相机系统
Default Perspective Camera
默认透视相机
tsx
<Canvas camera={{
fov: 75, // Field of view (degrees)
aspect: width/height, // Auto-calculated
near: 0.1, // Near clipping plane
far: 1000, // Far clipping plane
position: [0, 5, 10]
}} />tsx
<Canvas camera={{
fov: 75, // 视野角度(度)
aspect: width/height, // 自动计算
near: 0.1, // 近裁剪面
far: 1000, // 远裁剪面
position: [0, 5, 10]
}} />Custom Camera Component
自定义相机组件
tsx
import { PerspectiveCamera } from '@react-three/drei';
function Scene() {
return (
<>
<PerspectiveCamera
makeDefault // Set as active camera
fov={60}
position={[0, 2, 8]}
/>
{/* Scene contents */}
</>
);
}tsx
import { PerspectiveCamera } from '@react-three/drei';
function Scene() {
return (
<>
<PerspectiveCamera
makeDefault // 设置为活跃相机
fov={60}
position={[0, 2, 8]}
/>
{/* 场景内容 */}
</>
);
}Camera Access
相机访问
tsx
import { useThree } from '@react-three/fiber';
function CameraController() {
const { camera } = useThree();
useEffect(() => {
camera.lookAt(0, 0, 0);
}, [camera]);
return null;
}tsx
import { useThree } from '@react-three/fiber';
function CameraController() {
const { camera } = useThree();
useEffect(() => {
camera.lookAt(0, 0, 0);
}, [camera]);
return null;
}Lighting
灯光
Light Types
灯光类型
tsx
// Ambient: Uniform, directionless
<ambientLight intensity={0.4} color="#ffffff" />
// Directional: Sun-like, parallel rays
<directionalLight
position={[5, 10, 5]}
intensity={1}
castShadow
/>
// Point: Radiates from position
<pointLight
position={[0, 5, 0]}
intensity={1}
distance={20} // Range (0 = infinite)
decay={2} // Physical falloff
/>
// Spot: Cone-shaped
<spotLight
position={[0, 10, 0]}
angle={Math.PI / 6} // Cone angle
penumbra={0.5} // Edge softness
castShadow
/>
// Hemisphere: Sky/ground gradient
<hemisphereLight
skyColor="#87ceeb"
groundColor="#362907"
intensity={0.6}
/>tsx
// 环境光:均匀无方向
<ambientLight intensity={0.4} color="#ffffff" />
// 平行光:类似太阳光,光线平行
<directionalLight
position={[5, 10, 5]}
intensity={1}
castShadow
/>
// 点光源:从指定位置向外辐射
<pointLight
position={[0, 5, 0]}
intensity={1}
distance={20} // 照射范围(0表示无限)
decay={2} // 物理衰减
/>
// 聚光灯:锥形照射范围
<spotLight
position={[0, 10, 0]}
angle={Math.PI / 6} // 锥角
penumbra={0.5} // 边缘柔化度
castShadow
/>
// 半球光:天空/地面渐变光
<hemisphereLight
skyColor="#87ceeb"
groundColor="#362907"
intensity={0.6}
/>Shadow Setup
阴影设置
tsx
<Canvas shadows>
<directionalLight
castShadow
position={[10, 10, 10]}
shadow-mapSize={[2048, 2048]}
shadow-camera-far={50}
shadow-camera-left={-10}
shadow-camera-right={10}
shadow-camera-top={10}
shadow-camera-bottom={-10}
/>
<mesh castShadow>
<boxGeometry />
<meshStandardMaterial />
</mesh>
<mesh receiveShadow rotation={[-Math.PI / 2, 0, 0]} position={[0, -1, 0]}>
<planeGeometry args={[20, 20]} />
<meshStandardMaterial />
</mesh>
</Canvas>tsx
<Canvas shadows>
<directionalLight
castShadow
position={[10, 10, 10]}
shadow-mapSize={[2048, 2048]}
shadow-camera-far={50}
shadow-camera-left={-10}
shadow-camera-right={10}
shadow-camera-top={10}
shadow-camera-bottom={-10}
/>
<mesh castShadow>
<boxGeometry />
<meshStandardMaterial />
</mesh>
<mesh receiveShadow rotation={[-Math.PI / 2, 0, 0]} position={[0, -1, 0]}>
<planeGeometry args={[20, 20]} />
<meshStandardMaterial />
</mesh>
</Canvas>Render Loop (useFrame)
渲染循环(useFrame)
useFrametsx
import { useFrame, useThree } from '@react-three/fiber';
import { useRef } from 'react';
function RotatingBox() {
const meshRef = useRef<THREE.Mesh>(null!);
useFrame((state, delta) => {
// state: R3F state (camera, scene, clock, etc.)
// delta: Time since last frame (seconds)
meshRef.current.rotation.x += delta;
meshRef.current.rotation.y += delta * 0.5;
});
return (
<mesh ref={meshRef}>
<boxGeometry />
<meshNormalMaterial />
</mesh>
);
}useFrametsx
import { useFrame, useThree } from '@react-three/fiber';
import { useRef } from 'react';
function RotatingBox() {
const meshRef = useRef<THREE.Mesh>(null!);
useFrame((state, delta) => {
// state:R3F状态对象(相机、场景、时钟等)
// delta:距上一帧的时间(秒)
meshRef.current.rotation.x += delta;
meshRef.current.rotation.y += delta * 0.5;
});
return (
<mesh ref={meshRef}>
<boxGeometry />
<meshNormalMaterial />
</mesh>
);
}useFrame State Object
useFrame状态对象
tsx
useFrame((state) => {
state.clock // THREE.Clock
state.clock.elapsedTime // Total time (seconds)
state.camera // Active camera
state.scene // Scene object
state.gl // WebGLRenderer
state.size // { width, height }
state.viewport // { width, height, factor, distance }
state.mouse // Normalized mouse position [-1, 1]
state.raycaster // THREE.Raycaster
});tsx
useFrame((state) => {
state.clock // THREE.Clock
state.clock.elapsedTime // 总运行时间(秒)
state.camera // 活跃相机
state.scene // Scene对象
state.gl // WebGLRenderer
state.size // { width, height }
state.viewport // { width, height, factor, distance }
state.mouse // 归一化鼠标位置 [-1, 1]
state.raycaster // THREE.Raycaster
});Render Priority
渲染优先级
tsx
// Lower priority runs first, higher runs later
// Default is 0
useFrame(() => {
// Update physics
}, -1); // Runs before default
useFrame(() => {
// Update visuals
}, 0); // Default
useFrame(() => {
// Post-processing / camera
}, 1); // Runs after defaulttsx
// 优先级越低越先执行,越高越晚执行
// 默认优先级为0
useFrame(() => {
// 更新物理效果
}, -1); // 早于默认执行
useFrame(() => {
// 更新视觉效果
}, 0); // 默认优先级
useFrame(() => {
// 后处理 / 相机控制
}, 1); // 晚于默认执行Accessing Three.js Objects
访问Three.js对象
useThree Hook
useThree钩子
tsx
import { useThree } from '@react-three/fiber';
function SceneInfo() {
const {
gl, // WebGLRenderer
scene, // THREE.Scene
camera, // Active camera
size, // Canvas dimensions
viewport, // Viewport in Three.js units
clock, // THREE.Clock
set, // Update state
get, // Get current state
invalidate, // Request re-render (demand mode)
advance, // Advance one frame (never mode)
} = useThree();
return null;
}tsx
import { useThree } from '@react-three/fiber';
function SceneInfo() {
const {
gl, // WebGLRenderer
scene, // THREE.Scene
camera, // 活跃相机
size, // Canvas尺寸
viewport, // Three.js单位下的视口
clock, // THREE.Clock
set, // 更新状态
get, // 获取当前状态
invalidate, // 请求重渲染(demand模式)
advance, // 推进一帧(never模式)
} = useThree();
return null;
}Refs for Direct Access
通过Ref直接访问
tsx
import { useRef } from 'react';
import * as THREE from 'three';
function DirectAccess() {
const meshRef = useRef<THREE.Mesh>(null!);
const materialRef = useRef<THREE.MeshStandardMaterial>(null!);
useEffect(() => {
// Direct Three.js API access
meshRef.current.geometry.computeBoundingBox();
materialRef.current.needsUpdate = true;
}, []);
return (
<mesh ref={meshRef}>
<boxGeometry />
<meshStandardMaterial ref={materialRef} />
</mesh>
);
}tsx
import { useRef } from 'react';
import * as THREE from 'three';
function DirectAccess() {
const meshRef = useRef<THREE.Mesh>(null!);
const materialRef = useRef<THREE.MeshStandardMaterial>(null!);
useEffect(() => {
// 直接调用Three.js API
meshRef.current.geometry.computeBoundingBox();
materialRef.current.needsUpdate = true;
}, []);
return (
<mesh ref={meshRef}>
<boxGeometry />
<meshStandardMaterial ref={materialRef} />
</mesh>
);
}Events
事件
R3F provides pointer events on meshes:
tsx
<mesh
onClick={(e) => console.log('click', e.point)}
onContextMenu={(e) => console.log('right click')}
onDoubleClick={(e) => console.log('double click')}
onPointerOver={(e) => console.log('hover')}
onPointerOut={(e) => console.log('unhover')}
onPointerDown={(e) => console.log('down')}
onPointerUp={(e) => console.log('up')}
onPointerMove={(e) => console.log('move')}
>
<boxGeometry />
<meshStandardMaterial />
</mesh>R3F为网格提供指针事件支持:
tsx
<mesh
onClick={(e) => console.log('点击', e.point)}
onContextMenu={(e) => console.log('右键点击')}
onDoubleClick={(e) => console.log('双击')}
onPointerOver={(e) => console.log('悬停')}
onPointerOut={(e) => console.log('离开悬停')}
onPointerDown={(e) => console.log('按下')}
onPointerUp={(e) => console.log('抬起')}
onPointerMove={(e) => console.log('移动')}
>
<boxGeometry />
<meshStandardMaterial />
</mesh>Event Object
事件对象
tsx
onClick={(e) => {
e.stopPropagation(); // Stop event bubbling
e.point // THREE.Vector3 intersection point
e.distance // Distance from camera
e.object // Intersected object
e.face // Intersected face
e.faceIndex // Face index
e.uv // UV coordinates
e.camera // Camera used for raycasting
e.delta // Distance from last event
}}tsx
onClick={(e) => {
e.stopPropagation(); // 阻止事件冒泡
e.point // THREE.Vector3类型的交点
e.distance // 距相机的距离
e.object // 被交互的对象
e.face // 被交互的面
e.faceIndex // 面索引
e.uv // UV坐标
e.camera // 用于射线检测的相机
e.delta // 距上一次事件的距离
}}Suspense & Loading
Suspense与加载
R3F integrates with React Suspense for async loading:
tsx
import { Suspense } from 'react';
import { useLoader } from '@react-three/fiber';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
function Model() {
const gltf = useLoader(GLTFLoader, '/model.glb');
return <primitive object={gltf.scene} />;
}
function App() {
return (
<Canvas>
<Suspense fallback={<LoadingSpinner />}>
<Model />
</Suspense>
</Canvas>
);
}
function LoadingSpinner() {
const meshRef = useRef<THREE.Mesh>(null!);
useFrame((_, delta) => {
meshRef.current.rotation.z += delta * 2;
});
return (
<mesh ref={meshRef}>
<torusGeometry args={[1, 0.2, 16, 32]} />
<meshBasicMaterial color="white" wireframe />
</mesh>
);
}R3F集成React Suspense实现异步加载:
tsx
import { Suspense } from 'react';
import { useLoader } from '@react-three/fiber';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
function Model() {
const gltf = useLoader(GLTFLoader, '/model.glb');
return <primitive object={gltf.scene} />;
}
function App() {
return (
<Canvas>
<Suspense fallback={<LoadingSpinner />}>
<Model />
</Suspense>
</Canvas>
);
}
function LoadingSpinner() {
const meshRef = useRef<THREE.Mesh>(null!);
useFrame((_, delta) => {
meshRef.current.rotation.z += delta * 2;
});
return (
<mesh ref={meshRef}>
<torusGeometry args={[1, 0.2, 16, 32]} />
<meshBasicMaterial color="white" wireframe />
</mesh>
);
}Dependencies
依赖项
json
{
"dependencies": {
"@react-three/fiber": "^8.15.0",
"three": "^0.160.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/three": "^0.160.0"
}
}json
{
"dependencies": {
"@react-three/fiber": "^8.15.0",
"three": "^0.160.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/three": "^0.160.0"
}
}File Structure
文件结构
r3f-fundamentals/
├── SKILL.md
├── references/
│ ├── canvas-props.md # Complete Canvas prop reference
│ ├── hooks-api.md # useThree, useFrame, useLoader
│ └── event-system.md # Event handling deep-dive
└── scripts/
├── templates/
│ ├── basic-scene.tsx # Minimal starter
│ ├── lit-scene.tsx # With proper lighting
│ └── interactive.tsx # With events and animation
└── utils/
└── canvas-config.ts # Preset configurationsr3f-fundamentals/
├── SKILL.md
├── references/
│ ├── canvas-props.md # 完整Canvas属性参考
│ ├── hooks-api.md # useThree、useFrame、useLoader
│ └── event-system.md # 事件处理深度解析
└── scripts/
├── templates/
│ ├── basic-scene.tsx # 最小化启动模板
│ ├── lit-scene.tsx # 带完整灯光的模板
│ └── interactive.tsx # 带事件和动画的模板
└── utils/
└── canvas-config.ts # 预设配置Reference
参考文档
- — Complete Canvas configuration options
references/canvas-props.md - — All R3F hooks with examples
references/hooks-api.md - — Pointer events and raycasting
references/event-system.md
- — 完整Canvas配置选项
references/canvas-props.md - — 所有R3F钩子及示例
references/hooks-api.md - — 指针事件与射线检测
references/event-system.md