Was ist 3D im Web?
WebGL ermöglicht es dem Browser, hardwarebeschleunigtes 3D mithilfe der GPU zu rendern. Es ist leistungsstark, aber die reine API ist sehr ausführlich: Man muss Buffer verwalten, Shader schreiben und die Mathematik selbst handhaben. Three.js kapselt WebGL in einem benutzerfreundlichen Scene Graph, sodass man Objekte, Lichter und Kameras beschreiben kann und die Library den Rest erledigt.
Das Ergebnis ist, dass 3D im Web mittlerweile für Produktkonfiguratoren, Datenvisualisierungen, interaktives Storytelling, Spiele und immersive WebXR-Erlebnisse praktikabel ist. Es ist nicht die richtige Wahl für jede Website, aber wenn Bewegung und Raum die Geschichte besser erzählen als eine flache Seite, ist Three.js das Standard-Tool.
Scene, Camera, Renderer
Jede Three.js-App besteht aus drei Kernobjekten.
// setup.js
import * as THREE from "three";
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, innerWidth / innerHeight, 0.1, 100);
camera.position.set(0, 0, 3);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
Die scene ist der Container. Die camera definiert die Ansicht; PerspectiveCamera sorgt für eine realistische Tiefenwirkung, während OrthographicCamera nützlich für flache oder isometrische Ansichten ist. Der renderer zeichnet die Szene auf ein Canvas. Durch das Begrenzen der Pixel-Ratio wird verhindert, dass Bildschirme mit hoher Pixeldichte mehr Pixel rendern, als eigentlich nötig sind.
Meshes, Geometrie und Materialien
Ein sichtbares Objekt ist ein Mesh: eine Geometrie für seine Form und ein Material für seine Oberfläche.
// mesh.js
const cube = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshStandardMaterial({ color: 0x22c55e, roughness: 0.4 }),
);
cube.position.set(0, 0, 0);
scene.add(cube);
Three.js liefert viele integrierte Geometrien (Box, Sphere, Plane, Torus und mehr) sowie Materialien für verschiedene Looks mit. MeshStandardMaterial reagiert auf Licht und ist ein guter Standard; MeshBasicMaterial ignoriert die Beleuchtung und ist performanter. Meshes können gruppiert und verschachtelt werden, wodurch der Scene Graph entsteht, über den Transformationen vererbt werden.
Lichter und Schatten
Ohne Licht werden die meisten Materialien schwarz gerendert.
// lights.js
const ambient = new THREE.AmbientLight(0xffffff, 0.4);
const key = new THREE.DirectionalLight(0xffffff, 2.5);
key.position.set(2, 3, 2);
scene.add(ambient, key);
Lichter sind Objekte in der Szene, daher spielen ihre Position und ihr Typ eine wichtige Rolle. Schatten erfordern die Aktivierung von renderer.shadowMap sowie die entsprechende Markierung des Lichts, des Objekts und der Oberfläche. Da Schatten relativ rechenintensiv sind, sollten sie gezielt eingesetzt werden. Jedes Licht erhöht die Performance-Kosten, halten Sie die Anzahl daher gering.
Modelle und Texturen
In echten Projekten werden Assets normalerweise geladen, anstatt Geometrien manuell zu erstellen. glTF ist das Standardformat für 3D im Web.
// load.js
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
const loader = new GLTFLoader();
loader.load("/models/robot.glb", (gltf) => {
scene.add(gltf.scene);
});
Texturen werden ähnlich mit TextureLoader geladen, und RGBELoader oder PMREMGenerator können Environment Maps für realistische Reflexionen bereitstellen. Achten Sie darauf, die Größe von Modellen und Texturen moderat zu halten, da diese die Ladezeit und den Speicherverbrauch maßgeblich beeinflussen.
Der Animations-Loop
Animationen aktualisieren die Szene und rendern sie in jedem Frame neu.
// loop.js
const clock = new THREE.Clock();
renderer.setAnimationLoop(() => {
const delta = clock.getDelta();
cube.rotation.y += delta;
renderer.render(scene, camera);
});
Die Verwendung von delta sorgt dafür, dass die Bewegungsgeschwindigkeit unabhängig von der Frame-Rate konsistent bleibt. Wenn die Szene statisch ist, sollte on demand statt kontinuierlich gerendert werden: Rendern Sie nur nach einer Änderung, einer Interaktion mit den Controls oder einer Animation und stoppen Sie den Vorgang, wenn nichts passiert. Das schont den Akku und die GPU auf Mobilgeräten.
Interaktion
Um Objekte anklickbar oder hoverbar zu machen, verwenden Sie einen Raycaster.
// pick.js
const raycaster = new THREE.Raycaster();
const pointer = new THREE.Vector2();
addEventListener("pointerdown", (event) => {
pointer.x = (event.clientX / innerWidth) * 2 - 1;
pointer.y = -(event.clientY / innerHeight) * 2 + 1;
raycaster.setFromCamera(pointer, camera);
const hit = raycaster.intersectObjects(scene.children)[0];
if (hit) hit.object.material.color.set(0xf97316);
});
Das Raycasting von der Kamera durch den Pointer gibt die darunter liegenden Objekte zurück, was für die Auswahl, das Hervorheben und einfache Interaktionen ausreicht.
Performance und Cleanup
3D-Inhalte sind das Rechenintensivste, was die meisten Websites jemals rendern werden, daher ist Disziplin entscheidend.
- Dispose: Geometries, Materials und Textures müssen entsorgt werden, wenn Objekte entfernt werden; sie belegen Speicher auf der GPU.
- Wiederverwenden: Nutzen Sie Geometries und Materials über verschiedene Instanzen hinweg, anstatt ständig neue zu erstellen.
- Zusammenführen: Mergen Sie statische Geometries und nutzen Sie Instancing für wiederkehrende Objekte.
- Limitieren: Beschränken Sie die Anzahl der Lights und Objekte, die Schatten werfen.
- Pixel Ratio senken: Reduzieren Sie die Pixel Ratio auf Displays mit hoher Pixeldichte.
- On-Demand Rendering: Rendern Sie statische Szenen nur bei Bedarf.
- Pause: Pausieren Sie das Rendering, wenn das Canvas nicht im Sichtfeld (offscreen) ist.
// dispose.js
mesh.geometry.dispose();
mesh.material.dispose();
scene.remove(mesh);
Das Vergessen des Disposing ist die häufigste Ursache dafür, dass eine Three.js App langsam den gesamten verfügbaren Speicher verbraucht.
React Three Fiber
Mit React ermöglicht React Three Fiber das deklarative Rendern von Three.js. Die Szene wird somit über Komponenten beschrieben und lässt sich nahtlos in den React-State und den Lifecycle integrieren.
// Scene.jsx
import { Canvas } from "@react-three/fiber";
import { OrbitControls } from "@react-three/drei";
export function Scene() {
return (
<Canvas>
<ambientLight intensity={0.4} />
<directionalLight position={[2, 3, 2]} intensity={2.5} />
<mesh>
<boxGeometry />
<meshStandardMaterial color="#22c55e" />
</mesh>
<OrbitControls />
</Canvas>
);
}
Die drei-Helper bieten Controls, Environments und gängige Abstraktionen. Dies ist der empfohlene Weg, um Three.js in React einzusetzen.
Best Practices
- Begrenzen Sie die Pixel-Ratio (Clamp) und passen Sie die Größe des Renderers an das Fenster an.
- Verwenden Sie Geometrien und Materialien wieder; nutzen Sie Instancing für wiederkehrende Objekte.
- Löschen Sie GPU-Ressourcen, wenn Objekte entfernt werden.
- Halten Sie die Anzahl der Lichter und Schattenwerfer so gering wie möglich.
- Rendern Sie bei statischen Szenen nur bei Bedarf (Render on demand).
- Testen Sie auf echten Mobilgeräten der Mittelklasse.
- Stellen Sie einen Fallback bereit, falls WebGL nicht verfügbar ist.
Häufige Fehler
- Das Vergessen des Disposen, was zu GPU-Memory-Leaks führt.
- Kontinuierliches Rendering, obwohl sich nichts ändert.
- Erstellen von neuer Geometry oder Materials in jedem Frame.
- Hinzufügen zahlreicher Lights und Shadows ohne vorherige Performance-Messung.
- Laden von riesigen, unoptimierten Modellen und Texturen.
- Tests nur auf einem schnellen Desktop durchführen und dann für Mobile veröffentlichen.
Wie geht es weiter?
Three.js eröffnet dem Web eine völlig neue Dimension. Füge choreografierte Bewegungen mit dem Guide zu Advanced Animation hinzu, nutze React Three Fiber, falls du React verwendest, und behalte die Performance mit dem Guide zu Web Performance im Blick. Erstelle anschließend die kleinstmögliche Szene – einen beleuchteten Würfel, den du umkreisen kannst – und erweitere sie Konzept für Konzept.