2 min read
Web DevelopmentThree.js & React Three Fiber für 3D Web
3D Webentwicklung mit Three.js und React Three Fiber. WebGL/WebGPU, interaktive Szenen und Performance-Optimierung.
Three.jsReact Three Fiber3D WebWebGLWebGPUR3F

Three.js & React Three Fiber für 3D Web
Meta-Description: 3D Webentwicklung mit Three.js und React Three Fiber. WebGL/WebGPU, interaktive Szenen und Performance-Optimierung.
Keywords: Three.js, React Three Fiber, 3D Web, WebGL, WebGPU, R3F, Drei, Interactive 3D
Einführung
Three.js dominiert die 3D-Webentwicklung mit 270x mehr Downloads als Alternativen. React Three Fiber (R3F) bringt die deklarative React-Syntax in die 3D-Welt – perfekt für moderne Web-Projekte mit interaktiven Visualisierungen.
Architecture Overview
┌─────────────────────────────────────────────────────────────┐
│ THREE.JS / R3F ARCHITECTURE │
├─────────────────────────────────────────────────────────────┤
│ │
│ Application Layer: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ React Components / Hooks / State │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ R3F Layer: ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ React Three Fiber (React Renderer for Three.js) │ │
│ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │
│ │ │ Canvas │ │ Hooks │ │ Events │ │ │
│ │ │ (Root) │ │ (Frame) │ │(Pointer)│ │ │
│ │ └─────────┘ └─────────┘ └─────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ Drei (Helpers): │ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ OrbitControls | Environment | Text3D | useGLTF │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ Three.js Core: ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Scene | Camera | Renderer | Lights | Geometries │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ Graphics API: ▼ │
│ ┌───────────────────┬────────────────────┐ │
│ │ WebGL 2 │ WebGPU │ │
│ │ (Supported) │ (2026 Ready) │ │
│ └───────────────────┴────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘Setup & Installation
# React Three Fiber + Drei (Helpers)
npm install three @react-three/fiber @react-three/drei
# TypeScript Types
npm install -D @types/three
# Optional: Post-Processing, Physics
npm install @react-three/postprocessing
npm install @react-three/cannon// next.config.js (für Next.js)
const nextConfig = {
transpilePackages: ['three'],
webpack: (config) => {
config.externals.push({
'sharp': 'commonjs sharp',
'canvas': 'commonjs canvas',
});
return config;
}
};Basic Scene mit R3F
// components/Scene.tsx
'use client';
import { Canvas } from '@react-three/fiber';
import { OrbitControls, Environment, PerspectiveCamera } from '@react-three/drei';
import { Suspense } from 'react';
export function Scene() {
return (
<Canvas>
<PerspectiveCamera makeDefault position={[0, 2, 5]} />
<OrbitControls enableDamping dampingFactor={0.05} />
<Suspense fallback={<LoadingBox />}>
<Environment preset="sunset" />
<ambientLight intensity={0.5} />
<directionalLight position={[10, 10, 5]} intensity={1} castShadow />
<RotatingBox position={[-1.5, 0, 0]} />
<FloatingSphere position={[1.5, 0, 0]} />
<Floor />
</Suspense>
</Canvas>
);
}
function LoadingBox() {
return (
<mesh>
<boxGeometry args={[1, 1, 1]} />
<meshBasicMaterial color="gray" wireframe />
</mesh>
);
}Interaktive Objekte
// components/InteractiveObjects.tsx
'use client';
import { useRef, useState } from 'react';
import { useFrame } from '@react-three/fiber';
import { MeshWobbleMaterial, RoundedBox, Text } from '@react-three/drei';
import * as THREE from 'three';
interface BoxProps {
position: [number, number, number];
}
export function RotatingBox({ position }: BoxProps) {
const meshRef = useRef<THREE.Mesh>(null);
const [hovered, setHovered] = useState(false);
const [clicked, setClicked] = useState(false);
useFrame((state, delta) => {
if (meshRef.current) {
meshRef.current.rotation.x += delta * 0.5;
meshRef.current.rotation.y += delta * 0.3;
// Hover Animation
const scale = hovered ? 1.2 : 1;
meshRef.current.scale.lerp(new THREE.Vector3(scale, scale, scale), 0.1);
}
});
return (
<mesh
ref={meshRef}
position={position}
onClick={() => setClicked(!clicked)}
onPointerOver={() => setHovered(true)}
onPointerOut={() => setHovered(false)}
>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial
color={clicked ? '#ff6b6b' : hovered ? '#4ecdc4' : '#45b7d1'}
metalness={0.5}
roughness={0.2}
/>
</mesh>
);
}
export function FloatingSphere({ position }: BoxProps) {
const meshRef = useRef<THREE.Mesh>(null);
useFrame((state) => {
if (meshRef.current) {
// Floating Animation
meshRef.current.position.y = position[1] + Math.sin(state.clock.elapsedTime) * 0.3;
}
});
return (
<mesh ref={meshRef} position={position}>
<sphereGeometry args={[0.7, 32, 32]} />
<MeshWobbleMaterial
color="#9b59b6"
metalness={0.8}
roughness={0.1}
factor={0.5} // Wobble Intensity
speed={2} // Wobble Speed
/>
</mesh>
);
}
export function Floor() {
return (
<mesh rotation={[-Math.PI / 2, 0, 0]} position={[0, -1, 0]} receiveShadow>
<planeGeometry args={[20, 20]} />
<meshStandardMaterial color="#1a1a2e" metalness={0.2} roughness={0.8} />
</mesh>
);
}3D Model Loading (GLTF)
// components/Model.tsx
'use client';
import { useRef, useEffect } from 'react';
import { useGLTF, useAnimations, Clone } from '@react-three/drei';
import { useFrame } from '@react-three/fiber';
import * as THREE from 'three';
interface ModelProps {
url: string;
position?: [number, number, number];
scale?: number;
animate?: boolean;
}
export function Model({ url, position = [0, 0, 0], scale = 1, animate = true }: ModelProps) {
const group = useRef<THREE.Group>(null);
const { scene, animations } = useGLTF(url);
const { actions, names } = useAnimations(animations, group);
useEffect(() => {
// Erste Animation abspielen
if (animate && names.length > 0) {
actions[names[0]]?.play();
}
}, [actions, names, animate]);
// Shadow Setup
useEffect(() => {
scene.traverse((child) => {
if (child instanceof THREE.Mesh) {
child.castShadow = true;
child.receiveShadow = true;
}
});
}, [scene]);
return (
<group ref={group} position={position} scale={scale}>
<Clone object={scene} />
</group>
);
}
// Preload für bessere Performance
useGLTF.preload('/models/robot.glb');
// Mit Draco Compression
export function CompressedModel({ url }: { url: string }) {
const { scene } = useGLTF(url, true); // true = Draco Loader
return <primitive object={scene} />;
}Custom Shaders
// components/CustomShader.tsx
'use client';
import { useRef, useMemo } from 'react';
import { useFrame, extend } from '@react-three/fiber';
import { shaderMaterial } from '@react-three/drei';
import * as THREE from 'three';
// Custom Shader Material
const GradientMaterial = shaderMaterial(
// Uniforms
{
uTime: 0,
uColor1: new THREE.Color('#ff0000'),
uColor2: new THREE.Color('#0000ff'),
uIntensity: 1.0
},
// Vertex Shader
`
varying vec2 vUv;
varying vec3 vPosition;
void main() {
vUv = uv;
vPosition = position;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
// Fragment Shader
`
uniform float uTime;
uniform vec3 uColor1;
uniform vec3 uColor2;
uniform float uIntensity;
varying vec2 vUv;
varying vec3 vPosition;
void main() {
// Animated Gradient
float mixValue = sin(vUv.y * 3.14159 + uTime) * 0.5 + 0.5;
vec3 color = mix(uColor1, uColor2, mixValue);
// Wave Effect
float wave = sin(vPosition.x * 5.0 + uTime * 2.0) * 0.1;
color += wave * uIntensity;
gl_FragColor = vec4(color, 1.0);
}
`
);
// Extend für JSX Support
extend({ GradientMaterial });
// TypeScript Declaration
declare global {
namespace JSX {
interface IntrinsicElements {
gradientMaterial: any;
}
}
}
export function ShaderSphere() {
const materialRef = useRef<any>(null);
useFrame((state) => {
if (materialRef.current) {
materialRef.current.uTime = state.clock.elapsedTime;
}
});
return (
<mesh>
<sphereGeometry args={[1, 64, 64]} />
<gradientMaterial
ref={materialRef}
uColor1="#ff6b6b"
uColor2="#4ecdc4"
uIntensity={0.5}
/>
</mesh>
);
}Post-Processing Effects
// components/PostProcessing.tsx
'use client';
import { EffectComposer, Bloom, ChromaticAberration, Vignette } from '@react-three/postprocessing';
import { BlendFunction } from 'postprocessing';
export function Effects() {
return (
<EffectComposer>
{/* Bloom für leuchtende Effekte */}
<Bloom
intensity={1.5}
luminanceThreshold={0.9}
luminanceSmoothing={0.025}
mipmapBlur
/>
{/* Chromatische Aberration */}
<ChromaticAberration
blendFunction={BlendFunction.NORMAL}
offset={[0.002, 0.002]}
/>
{/* Vignette */}
<Vignette
offset={0.3}
darkness={0.5}
blendFunction={BlendFunction.NORMAL}
/>
</EffectComposer>
);
}
// Verwendung
function SceneWithEffects() {
return (
<Canvas>
<Scene />
<Effects />
</Canvas>
);
}Physics mit Cannon
// components/PhysicsScene.tsx
'use client';
import { Physics, usePlane, useBox, useSphere } from '@react-three/cannon';
import { useRef } from 'react';
import * as THREE from 'three';
export function PhysicsScene() {
return (
<Physics gravity={[0, -9.81, 0]}>
<PhysicsGround />
<PhysicsBox position={[0, 5, 0]} />
<PhysicsBox position={[0.5, 7, 0]} />
<PhysicsBall position={[-0.5, 10, 0]} />
</Physics>
);
}
function PhysicsGround() {
const [ref] = usePlane<THREE.Mesh>(() => ({
rotation: [-Math.PI / 2, 0, 0],
position: [0, 0, 0]
}));
return (
<mesh ref={ref} receiveShadow>
<planeGeometry args={[20, 20]} />
<meshStandardMaterial color="#333" />
</mesh>
);
}
function PhysicsBox({ position }: { position: [number, number, number] }) {
const [ref] = useBox<THREE.Mesh>(() => ({
mass: 1,
position,
args: [1, 1, 1]
}));
return (
<mesh ref={ref} castShadow>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color="#ff6b6b" />
</mesh>
);
}
function PhysicsBall({ position }: { position: [number, number, number] }) {
const [ref] = useSphere<THREE.Mesh>(() => ({
mass: 2,
position,
args: [0.5]
}));
return (
<mesh ref={ref} castShadow>
<sphereGeometry args={[0.5, 32, 32]} />
<meshStandardMaterial color="#4ecdc4" />
</mesh>
);
}Performance Optimierung
// components/OptimizedScene.tsx
'use client';
import { useRef, useMemo } from 'react';
import { useFrame } from '@react-three/fiber';
import { Instances, Instance, Detailed, useGLTF } from '@react-three/drei';
import * as THREE from 'three';
// Instancing für viele gleiche Objekte
export function InstancedCubes({ count = 1000 }) {
const positions = useMemo(() => {
return Array.from({ length: count }, () => ({
position: [
(Math.random() - 0.5) * 20,
(Math.random() - 0.5) * 20,
(Math.random() - 0.5) * 20
] as [number, number, number],
rotation: [
Math.random() * Math.PI,
Math.random() * Math.PI,
Math.random() * Math.PI
] as [number, number, number],
scale: 0.5 + Math.random() * 0.5
}));
}, [count]);
return (
<Instances limit={count} castShadow receiveShadow>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color="#45b7d1" />
{positions.map((props, i) => (
<Instance
key={i}
position={props.position}
rotation={props.rotation}
scale={props.scale}
/>
))}
</Instances>
);
}
// Level of Detail (LOD)
export function LODModel() {
return (
<Detailed distances={[0, 10, 25, 50]}>
{/* Höchste Qualität (nah) */}
<mesh>
<sphereGeometry args={[1, 64, 64]} />
<meshStandardMaterial color="red" />
</mesh>
{/* Mittlere Qualität */}
<mesh>
<sphereGeometry args={[1, 32, 32]} />
<meshStandardMaterial color="red" />
</mesh>
{/* Niedrige Qualität */}
<mesh>
<sphereGeometry args={[1, 16, 16]} />
<meshStandardMaterial color="red" />
</mesh>
{/* Sehr niedrige Qualität (weit) */}
<mesh>
<sphereGeometry args={[1, 8, 8]} />
<meshStandardMaterial color="red" />
</mesh>
</Detailed>
);
}
// Lazy Loading
import { lazy, Suspense } from 'react';
const HeavyModel = lazy(() => import('./HeavyModel'));
export function LazyScene() {
return (
<Suspense fallback={<LoadingIndicator />}>
<HeavyModel />
</Suspense>
);
}Best Practices
| Aspect | Recommendation |
|---|---|
| **Geometry** | Instancing für viele gleiche Objekte |
| **Textures** | Compressed (WebP), Power of 2 |
| **Models** | Draco compression, LOD |
| **Shadows** | Nur wo nötig, Shadow Map Size |
| **Animations** | useFrame statt setInterval |
| **State** | Zustand außerhalb des Render Loops |
| **Cleanup** | dispose() für Geometries/Materials |
Fazit
Three.js + React Three Fiber bietet:
- Deklarative Syntax: React-Komponenten für 3D
- Ecosystem: Drei, Cannon, Postprocessing
- WebGPU Ready: Zukunftssicher mit WebGPU Support
- Performance: Instancing, LOD, Lazy Loading
Die beste Kombination für 3D im Web.
Bildprompts
- "Interactive 3D scene with rotating objects, React Three Fiber demo"
- "WebGL shader effect with gradient colors, custom material"
- "Physics simulation with falling objects, cannon.js integration"