下面,我们来系统的梳理关于 React Three Fiber:WebGL 与 React 的基本知识点:
一、React Three Fiber 核心概念
1.1 什么是 React Three Fiber?
React Three Fiber(R3F)是一个用于 Three.js 的 React 渲染器,它允许您使用声明式的 React 组件方式来创建 3D 场景。
1.2 核心优势
- 声明式语法:使用 JSX 描述 3D 场景
- 自动管理:自动处理渲染循环、资源清理
- Hooks 支持:完整的 React Hooks 集成
- TypeScript 支持:完整的类型定义
- 生态系统:丰富的扩展和插件
1.3 与传统 Three.js 对比
特性 | Three.js | React Three Fiber |
---|---|---|
语法 | 命令式 | 声明式 |
状态管理 | 手动 | 自动 |
组件化 | 无 | 完整组件支持 |
学习曲线 | 陡峭 | 平缓 |
开发效率 | 较低 | 较高 |
二、环境搭建与基础配置
2.1 安装依赖
npm install three @react-three/fiber @react-three/drei
# 可选:物理引擎、后期处理等
npm install @react-three/cannon @react-three/postprocessing
2.2 基础场景设置
import { Canvas } from '@react-three/fiber';
import { OrbitControls, Sky } from '@react-three/drei';function Scene() {return (<Canvascamera={{ position: [0, 0, 5], fov: 75 }}shadowsgl={{ alpha: false, antialias: true }}><color attach="background" args={['#f0f0f0']} /><ambientLight intensity={0.5} /><directionalLightposition={[10, 10, 5]}intensity={1}castShadowshadow-mapSize={[1024, 1024]}/><mesh position={[0, 0, 0]} castShadow receiveShadow><boxGeometry args={[1, 1, 1]} /><meshStandardMaterial color="orange" /></mesh><mesh position={[0, -1, 0]} rotation={[-Math.PI / 2, 0, 0]} receiveShadow><planeGeometry args={[10, 10]} /><meshStandardMaterial color="green" /></mesh><OrbitControls enablePan enableZoom enableRotate /><Sky sunPosition={[10, 10, 5]} /></Canvas>);
}
2.3 类型安全配置 (TypeScript)
// types/three.d.ts
import { ThreeElements } from '@react-three/fiber';declare global {namespace JSX {interface IntrinsicElements extends ThreeElements {customGeometry: any;}}
}
三、核心组件与 Hooks
3.1 基础几何体组件
import { useRef } from 'react';
import { useFrame } from '@react-three/fiber';function RotatingBox() {const meshRef = useRef<THREE.Mesh>(null);useFrame((state, delta) => {if (meshRef.current) {meshRef.current.rotation.x += delta;meshRef.current.rotation.y += delta * 0.5;}});return (<mesh ref={meshRef} position={[0, 1, 0]}><boxGeometry args={[1, 1, 1]} /><meshStandardMaterial color="hotpink" /></mesh>);
}
3.2 灯光系统
function LightingSetup() {return (<><ambientLight intensity={0.2} /><directionalLightposition={[5, 5, 5]}intensity={1}castShadowshadow-camera-far={50}shadow-camera-left={-10}shadow-camera-right={10}shadow-camera-top={10}shadow-camera-bottom={-10}/><pointLight position={[-5, 5, -5]} intensity={0.5} color="blue" /><spotLightposition={[0, 10, 0]}angle={0.3}penumbra={1}intensity={1}castShadow/></>);
}
3.3 相机与控制
import { PerspectiveCamera, OrbitControls } from '@react-three/drei';function CameraSetup() {return (<><PerspectiveCameramakeDefaultposition={[0, 2, 10]}fov={75}near={0.1}far={1000}/><OrbitControlsenableDampingdampingFactor={0.05}minDistance={5}maxDistance={20}maxPolarAngle={Math.PI / 2}/></>);
}
四、高级几何体与材质
4.1 自定义几何体
import { useMemo } from 'react';
import * as THREE from 'three';function CustomGeometry() {const geometry = useMemo(() => {const geom = new THREE.BufferGeometry();const vertices = new Float32Array([-1.0, -1.0, 1.0, // v01.0, -1.0, 1.0, // v11.0, 1.0, 1.0, // v2-1.0, 1.0, 1.0, // v3]);const indices = [0, 1, 2, 2, 3, 0];geom.setAttribute('position', new THREE.BufferAttribute(vertices, 3));geom.setIndex(indices);geom.computeVertexNormals();return geom;}, []);return (<mesh geometry={geometry}><meshStandardMaterial color="cyan" side={THREE.DoubleSide} /></mesh>);
}
4.2 高级材质系统
import { useTexture } from '@react-three/drei';function TexturedSphere() {const [colorMap, normalMap, roughnessMap] = useTexture(['/textures/diffuse.jpg','/textures/normal.jpg','/textures/roughness.jpg']);return (<mesh position={[2, 0, 0]}><sphereGeometry args={[1, 32, 32]} /><meshStandardMaterialmap={colorMap}normalMap={normalMap}roughnessMap={roughnessMap}roughness={0.8}metalness={0.2}/></mesh>);
}
4.3 Shader 材质
import { useFrame } from '@react-three/fiber';function ShaderSphere() {const materialRef = useRef<THREE.ShaderMaterial>(null);useFrame((state) => {if (materialRef.current) {materialRef.current.uniforms.time.value = state.clock.elapsedTime;}});const shaderArgs = useMemo(() => ({uniforms: {time: { value: 0 },color: { value: new THREE.Color('purple') }},vertexShader: `varying vec2 vUv;void main() {vUv = uv;gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);}`,fragmentShader: `uniform float time;uniform vec3 color;varying vec2 vUv;void main() {vec2 uv = vUv * 2.0 - 1.0;float d = length(uv);float glow = exp(-d * 3.0) * 0.5 * (sin(time * 2.0) + 1.0);gl_FragColor = vec4(color + vec3(glow), 1.0);}`}), []);return (<mesh><sphereGeometry args={[1, 64, 64]} /><shaderMaterial ref={materialRef} args={[shaderArgs]} /></mesh>);
}
五、动画与交互
5.1 使用 useFrame 动画
function AnimatedMesh() {const meshRef = useRef<THREE.Mesh>(null);useFrame((state, delta) => {if (meshRef.current) {meshRef.current.rotation.x = Math.sin(state.clock.elapsedTime) * 0.5;meshRef.current.position.y = Math.cos(state.clock.elapsedTime) * 0.5;}});return (<mesh ref={meshRef}><torusKnotGeometry args={[1, 0.4, 128, 32]} /><meshStandardMaterial color="hotpink" /></mesh>);
}
5.2 GSAP 集成
import { useGSAP } from '@react-three/gsap';
import gsap from 'gsap';function GSAPAnimation() {const groupRef = useRef<THREE.Group>(null);useGSAP(() => {if (groupRef.current) {gsap.to(groupRef.current.rotation, {y: Math.PI * 2,duration: 2,repeat: -1,ease: "power1.inOut"});}}, []);return (<group ref={groupRef}><mesh><icosahedronGeometry args={[1]} /><meshNormalMaterial /></mesh></group>);
}
5.3 用户交互处理
function InteractiveCube() {const [hovered, setHovered] = useState(false);const [clicked, setClicked] = useState(false);const meshRef = useRef<THREE.Mesh>(null);useFrame(() => {if (meshRef.current) {meshRef.current.rotation.x += 0.01;}});return (<meshref={meshRef}position={[0, 0, 0]}scale={clicked ? 1.5 : 1}onClick={() => setClicked(!clicked)}onPointerOver={() => setHovered(true)}onPointerOut={() => setHovered(false)}><boxGeometry args={[1, 1, 1]} /><meshStandardMaterial color={hovered ? 'hotpink' : 'orange'} /></mesh>);
}
六、性能优化
6.1 实例化渲染
import { Instances, Instance } from '@react-three/drei';function InstancedCubes() {const count = 1000;const instances = useMemo(() => {const positions = [];for (let i = 0; i < count; i++) {positions.push([(Math.random() - 0.5) * 20,(Math.random() - 0.5) * 20,(Math.random() - 0.5) * 20]);}return positions;}, []);return (<Instances range={count}><boxGeometry args={[0.5, 0.5, 0.5]} /><meshStandardMaterial color="orange" />{instances.map((position, i) => (<Instancekey={i}position={position}rotation={[Math.random(), Math.random(), Math.random()]}/>))}</Instances>);
}
6.2 LOD(Level of Detail)系统
import { LOD } from '@react-three/drei';function LODModel() {return (<LOD><mesh><sphereGeometry args={[1, 32, 32]} /><meshStandardMaterial color="red" /></mesh><mesh><sphereGeometry args={[1, 16, 16]} /><meshStandardMaterial color="blue" /></mesh><mesh><sphereGeometry args={[1, 8, 8]} /><meshStandardMaterial color="green" /></mesh></LOD>);
}
6.3 后期处理优化
import { EffectComposer, Bloom, ChromaticAberration } from '@react-three/postprocessing';
import { BlendFunction } from 'postprocessing';function PostProcessing() {return (<EffectComposer><Bloomintensity={0.5}luminanceThreshold={0.6}luminanceSmoothing={0.9}height={300}/><ChromaticAberrationblendFunction={BlendFunction.NORMAL}offset={[0.002, 0.002]}/></EffectComposer>);
}
七、物理引擎集成
7.1 使用 @react-three/cannon
import { Physics, useBox, usePlane } from '@react-three/cannon';function PhysicsScene() {return (<Physics gravity={[0, -9.81, 0]}><Floor /><Box position={[0, 5, 0]} /><Box position={[1, 8, 0]} /></Physics>);
}function Floor() {const [ref] = usePlane(() => ({rotation: [-Math.PI / 2, 0, 0],position: [0, -2, 0]}));return (<mesh ref={ref} receiveShadow><planeGeometry args={[20, 20]} /><meshStandardMaterial color="green" /></mesh>);
}function Box({ position }) {const [ref] = useBox(() => ({mass: 1,position,restitution: 0.5}));return (<mesh ref={ref} castShadow><boxGeometry args={[1, 1, 1]} /><meshStandardMaterial color="orange" /></mesh>);
}
7.2 物理约束与交互
function PhysicsChain() {const [ref, api] = useBox(() => ({mass: 1,position: [0, 10, 0]}));useFrame(() => {api.applyForce([0, 0, 0.1], [0, 0, 0]);});return (<mesh ref={ref}><boxGeometry args={[0.5, 0.5, 0.5]} /><meshStandardMaterial color="red" /></mesh>);
}
八、资源管理与加载
8.1 使用 useLoader
import { useLoader } from '@react-three/fiber';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
import { Suspense } from 'react';function Model({ url }) {const gltf = useLoader(GLTFLoader, url, (loader) => {const dracoLoader = new DRACOLoader();dracoLoader.setDecoderPath('/draco/');loader.setDRACOLoader(dracoLoader);});return <primitive object={gltf.scene} />;
}function Scene() {return (<Suspense fallback={<LoadingFallback />}><Model url="/models/robot.glb" /></Suspense>);
}function LoadingFallback() {return (<mesh><boxGeometry args={[1, 1, 1]} /><meshStandardMaterial color="gray" /></mesh>);
}
8.2 预加载资源
import { useGLTF } from '@react-three/drei';function PreloadedModel() {const { nodes, materials } = useGLTF('/model.glb');return (<group><mesh geometry={nodes.mesh.geometry} material={materials.material} /></group>);
}// 预加载
useGLTF.preload('/model.glb');
九、调试与开发工具
9.1 性能监视器
import { Perf } from 'r3f-perf';function DebugScene() {return (<><Perf position="top-left" />{/* 场景内容 */}</>);
}
9.2 Gizmos 与辅助工具
import { GizmoHelper, GizmoViewport, Grid, TransformControls } from '@react-three/drei';function DebugTools() {return (<><GridcellSize={1}cellThickness={1}cellColor="#6f6f6f"sectionSize={5}sectionThickness={2}sectionColor="#9d4b4b"fadeDistance={30}fadeStrength={1}/><GizmoHelper alignment="bottom-right" margin={[80, 80]}><GizmoViewport /></GizmoHelper></>);
}
9.3 自定义调试组件
function DebugInfo() {useFrame((state) => {console.log('Frame time:', state.clock.getDelta());console.log('FPS:', 1 / state.clock.getDelta());});return null;
}
十、案例:交互式 3D 产品展示
10.1 产品查看器
import { Environment, PresentationControls } from '@react-three/drei';function ProductViewer() {const { nodes, materials } = useGLTF('/product.glb');const [currentColor, setCurrentColor] = useState('#ff6b6b');return (<Canvas camera={{ position: [0, 0, 5], fov: 50 }}><Environment preset="studio" /><PresentationControlsglobalzoom={0.8}rotation={[0, -Math.PI / 4, 0]}polar={[-Math.PI / 4, Math.PI / 4]}azimuth={[-Math.PI / 4, Math.PI / 4]}><mesh geometry={nodes.product.geometry}><meshStandardMaterialcolor={currentColor}roughness={0.2}metalness={0.8}/></mesh></PresentationControls><ColorPicker onColorChange={setCurrentColor} /></Canvas>);
}function ColorPicker({ onColorChange }) {const colors = ['#ff6b6b', '#4ecdc4', '#45b7d1', '#f9c74f'];return (<div style={{ position: 'absolute', bottom: 20, left: 20 }}>{colors.map(color => (<buttonkey={color}style={{ backgroundColor: color, margin: 5 }}onClick={() => onColorChange(color)}/>))}</div>);
}
10.2 3D 数据可视化
function DataVisualization({ data }) {const barsRef = useRef<THREE.InstancedMesh>(null);useFrame(() => {if (barsRef.current) {data.forEach((value, i) => {const scale = new THREE.Vector3(0.5, value, 0.5);const position = new THREE.Vector3(i - data.length / 2, value / 2, 0);barsRef.current.setMatrixAt(i, new THREE.Matrix4().compose(position, new THREE.Quaternion(), scale));});barsRef.current.instanceMatrix.needsUpdate = true;}});return (<instancedMesh ref={barsRef} args={[undefined, undefined, data.length]}><boxGeometry /><meshStandardMaterial color="orange" /></instancedMesh>);
}
十一、部署与性能考虑
11.1 构建优化
// vite.config.js (Vite)
export default {build: {rollupOptions: {external: ['three', '@react-three/fiber']}}
};// webpack.config.js (Webpack)
module.exports = {externals: {three: 'THREE','@react-three/fiber': 'ReactThreeFiber'}
};
11.2 代码分割与懒加载
import { lazy, Suspense } from 'react';const HeavyModel = lazy(() => import('./HeavyModel'));function OptimizedScene() {return (<Suspense fallback={<LoadingSpinner />}><HeavyModel /></Suspense>);
}
十二、总结
核心优势
- 开发体验:声明式语法,自动资源管理
- 性能优化:智能渲染,实例化支持
- 生态系统:丰富的扩展和工具
- TypeScript:完整的类型支持
- 社区支持:活跃的开发和用户社区
适用场景
- 产品展示:3D 产品配置器和查看器
- 数据可视化:3D 图表和数据分析
- 游戏开发:WebGL 游戏和交互体验
- 建筑可视化:3D 建筑展示和漫游
- 艺术创作:交互式艺术装置和展览