Lerne Coding
WebGL - three.js: Eine Einführung in die Erstellung von 3D-Welten

3D Welten erschaffen mit three.js und WebGL

Inhaltsverzeichnis
[[TABLE OF CONTENTS]]
access_timeGeschätzte Lesezeit ca. Minuten

Wenn du dich für die Welt des 3D-Designs und der Animationen interessierst, bist du hier genau richtig. In dieser Erklärung werde ich dir zeigen, wie du mit der JavaScript-Bibliothek three.js 3D-Welten erstellen und animieren kannst.

Zuallererst: Was ist die Web Graphics Library (WebGL)? Mit dieser Technologie kann man interaktive 2D und 3D Grafiken direkt im Browser anzeigen. Und das ohne eine zusätzliche Software.

Ein 3D Viewer von three.js mit einer Pyramide, Würfel und Kugel
Ein 3D Viewer von three.js mit einer Pyramide, Würfel und Kugel

Der Funktionsumfang kommt aber mit einem Preis: Die Menge an Code und Hintergrundwissen, die man benötigt, um einfache Szenen zu erstellen, ist ziemlich groß.

Ein Framework wie three.js erleichtert die ganzen Grundlagen und bietet viele vorgefertigte Funktion, Formen, Kameras etc. Außerdem essenziell: Es gibt eine große Community mit Fragen, Antworten und Anleitungen, die dir immer weiterhelfen können.

WebGL JavaScript Framework: three.js

Three.js ist eine JavaScript-Bibliothek, mit der du 3D-Grafiken direkt im Webbrowser anzeigen kannst. Außerdem ist es Open-Source. Stell dir die gesamte 3D-Welt einfach wie ein Filmset vor: „Licht, Kamera, Action!“. Was benötigt man für ein Filmset? Eine Szene, Schauspieler, Licht und eine Kamera. Und genau das werden wir auch in three.js erstellen, nur dass unser Schauspieler erst mal ein einfacher Würfel ist.

10 Zylinder von unterschiedlichen Größen als Gitterstruktur
10 Zylinder von unterschiedlichen Größen als Gitterstruktur

Mit three.js und WebGL können Entwickler komplexe visuelle Effekte erzeugen, interaktive Animationen erstellen und virtuelle Realitäten schaffen.

Zum Beispiel:

  • Es können 3D-Modelle von Räumen oder Gebäuden erstellt und in Echtzeit präsentiert werden: IKEA benutzt das in dem 3D Küchenplaner.
  • Einer meiner Favoriten was Animationen angeht: Diese Seite eines Motion Designers verwendet three.js für das komplette Userinterface.

Installation von three.js

Bevor wir beginnen können, müssen wir three.js in unser Projekt einbinden. Dazu können wir entweder die three.js-Dateien herunterladen oder über einen CDN-Link einbinden. Die detaillierte Anleitung zur Installation findest du auf der three.js-Website

Sobald du die Dateien in deine HTML-Datei eingebunden hast, können wir mit dem ersten Projekt starten.

Projekt #1: „Hello World“ Kugel

Beginnen wir also mit unserem Filmset und bauen eine Szene. Die Grundlage einer jeden 3D-Szene in three.js ist die Scene-Klasse. Diese Scene-Klasse repräsentiert die 3D-Welt, in der sich unsere Objekte befinden werden. Um eine Scene-Instanz zu erstellen, müssen wir einfach den folgenden Code ausführen:

const scene = new THREE.Scene();

Dies erstellt eine leere Szene, die wir nun mit Objekten füllen können.

Erstellen einer Kamera

Damit überhaupt was zu sehen ist, brauchen wir eine Kamera. Das ist der Blickwinkel, aus dem wir die ganze Szene betrachten. In three.js können wir verschiedene Kameratypen verwenden, darunter die PerspectiveCamera und die OrthographicCamera. Um eine PerspectiveCamera zu erstellen, füge den Code ein:

const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;

Hier legen wir das Sichtfeld auf 75 Grad fest, und die near- und far-Ebenen auf 0,1 und 1000. Diese Werte bestimmen, welche Objekte innerhalb des Kamera-Sichtfelds gerendert werden und welche nicht. Außerdem verschieben wir die Kamera in Z-Richtung nach oben, damit wir auf das Objekt schauen können.

Eine Kamera in der 3D Welt: Der weiße Strahl ist das Zentrum des Blickfeldes, die orangenen Linien zeigen die 4 Ecken.
Eine Kamera in der 3D Welt: Der weiße Strahl ist das Zentrum des Blickfeldes, die orangenen Linien zeigen die 4 Ecken.

Von 3D zu 2D: Renderer

Um unsere Szene zu rendern, benötigen wir einen Renderer. Der Renderer zeichnet die Szene auf den Bildschirm. In three.js gibt es verschiedene Typen, darunter den WebGLRenderer, der auf WebGL basiert. Um einen solchen zu erstellen, müssen wir den folgenden Code ausführen:

const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

Hier legen wir die Größe des Renderers auf die Größe des Browserfensters fest und fügen das Renderer-Element unserem HTML-Dokument hinzu. Hierfür wird im Hintergrund ein Canvas Element erzeugt. Also eine Leinwand auf der das Bild der 3D-Szene gezeichnet wird.

Erstellen von Objekten

Jetzt können wir der Szene Objekte hinzufügen. Three.js verfügt über viele integrierte geometrische Formen wie Würfel, Kugeln, Zylinder usw. Man kann auch eigene Modelle und Texturen erstellen und verwenden. Um unter anderem einen Würfel hinzuzufügen, können wir den folgenden Code ausführen:

const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// Try to render:
// renderer.render(scene, camera);

Hier erstellt man eine Würfelgeometrie, eine Materialtextur und ein Mesh, das die Geometrie und das Material miteinander verbindet. Dann fügen wir den Würfel der Szene hinzu.

Nachdem der Würfel in die Szene eingefügt wurde, wird dieser im Zentrum platziert
Nachdem der Würfel in die Szene eingefügt wurde, wird dieser im Zentrum platziert

Wenn man an dieser Stelle renderer.render() ausführt, sieht man noch nichts. Einfach nur ein schwarzer Bildschirm. Wie oben beschrieben benötigen wir in einer Szene auch immer ein Licht, denn ansonsten sieht die Kamera nichts. Ein HemisphereLight beleuchtet die obere Hemisphäre der 3D gleichmäßig. Der erste Wert ist die Farbe des „Himmels“, die zweite die des „Bodens“. Der dritte Wert ist die Stärke der Beleuchtung.

const light = new THREE.HemisphereLight(0xffffff, 0x080820, 1);
scene.add(light);

// Try to render:
// renderer.render(scene, camera);

Jetzt sollte man die Szene mit dem Würfel endlich sehen. Als Nächstes beschäftigen wir uns mit der Animation.

Animationen erstellen

Nun können wir Szene und Objekte animieren. Three.js bietet verschiedene Animationsmethoden, darunter die requestAnimationFrame-Methode, um eine kontinuierliche Animation zu erstellen. Um insbesondere den Würfel kontinuierlich rotieren zu lassen, können wir den folgenden Code ausführen:

function animate() {
  requestAnimationFrame(animate);
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;
  renderer.render(scene, camera);
}
animate();

Hier erstellen wir eine Funktion animate(), die die requestAnimationFrame-Methode aufruft und den Würfel um 0,01 Grad um die x- und y-Achse dreht. Dann rendern wir die Szene mit dem Renderer.

Wichtig:

hier verwendt man die Funktion animate als callback in requestAnimationFrame. Diese Animations-Funktion wird also immer wieder aufgerufen und wir starten damit die Uhr der 3D-Welt.

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
camera.position.z = 5;
const renderer = new THREE.WebGLRenderer();

renderer.setSize(window.innerWidth, window.innerHeight);
document.querySelector('.example-code').appendChild(renderer.domElement);

const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0x00aa00 });
const cube = new THREE.Mesh(geometry, material);
const light = new THREE.HemisphereLight(0xffffff, 0x080820, 1);
scene.add(light);
scene.add(cube);

function animate() {
  requestAnimationFrame(animate);
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;
  renderer.render(scene, camera);
}
animate();

Projekt #2: 3D Welle

Der drehende Zylinder ist natürlich ein schönes „Hello World“-Beispiel, aber da gibt es noch sehr viel mehr: Das zweite Projekt soll eine 3D-Welle mit mehreren Zylindern darstellen. Wir starten wieder wie zuvor mit der Szene, Kamera und Renderer:

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
  50,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
camera.position.z = 50;
camera.position.y = 20;
camera.position.x = 40;
camera.rotation.x = -0.5;
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

Hier hat sich die Kamera Perspektive und Position verändert. Da wir mehrere Objekte sehen wollen sind die Werte x,y und z weiter vom Zentrum entfernt.

Das Objekt Array

Als Nächstes erstellen wir wieder Geometrie und Material. Dieses Mal nutzen wir eine CylinderGeometry mit dem Radius 2, Höhe 5 und 30 Segmenten.

Das Material hat jetzt zusätzlich die Eigenschaft wireframe. Damit wird das Objekt als Gitter dargestellt. Das Licht wird genauso wie zuvor hinzugefügt.

Dann erstellt man ein Array, was mit zehn Zylinder-Objekten gefüllt wird. Wichtig ist, dass die X-Position bei jedem Objekt verschoben wird, damit alle nebeneinander stehen.

const geometry = new THREE.CylinderGeometry(2, 2, 5, 30);
const material = new THREE.MeshBasicMaterial({
  color: 0x0099aa,
  wireframe: true
});
const light = new THREE.HemisphereLight(0xffffff, 0x080820, 1);
scene.add(light);

let objArray = [];
for (let i = 0; i < 10; ++i) {
  const cylinder = new THREE.Mesh(geometry, material);
  cylinder.position.x = 8 * i;
  scene.add(cylinder);
  objArray.push(cylinder);
}
Das Zwischenergebnis sind 10 Zylinder nebeinander. Die Wireframe (Gitterstruktur) der einzelnen Objekte mach sie durchsichtig.
Das Zwischenergebnis sind 10 Zylinder nebeinander. Die Wireframe (Gitterstruktur) der einzelnen Objekte mach sie durchsichtig.

Die Animation

Jetzt kommen wir zum interessanten Teil: Die Zylinder sollen sich wellenförmig vergrößern und verkleinern.

Dafür wird die .scale Eigenschaft der Objekte benutzt. Die Y-Skalierung wird also mit jedem Render-Durchgang neu berechnet. Die animate Funktion hat hier einen neuen Parameter. time beschreibt die aktuelle Zeit in des Render-Durchgangs in Millisekunden.

Es wird also eine Sinus-Funktion in Abhängigkeit der Zeit und der X-Position berechnet. Die beiden Faktoren 0.002 und 0.02 sind so gewählt, dass die Animation schön langsam und flüssig aussieht.

sin(0.002*time+0.02*PositionX)
sin(0.002*time+0.02*PositionX)

Höhere Werte bei der Zeit lassen die Animation schneller ablaufen. Höhere Werte bei der Position lassen den Unterschied der einzelnen Zylinder größer werden.

function animate(time) {
  requestAnimationFrame(animate);
  for (let obj of objArray) {
    obj.scale.y = 0.5 * Math.sin(0.002 * time + 0.02 * obj.position.x) + 1;
  }
  renderer.render(scene, camera);
}
animate();
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
  50,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
camera.position.z = 50;
camera.position.y = 20;
camera.position.x = 40;
camera.rotation.x = -0.5;
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.querySelector('.example-code').appendChild(renderer.domElement);
const geometry = new THREE.CylinderGeometry(2, 2, 5, 30);
const material = new THREE.MeshBasicMaterial({
  color: 0x0099aa,
  wireframe: true
});
const light = new THREE.HemisphereLight(0xffffff, 0x080820, 1);
scene.add(light);

let objArray = [];
for (let i = 0; i < 10; ++i) {
  const cylinder = new THREE.Mesh(geometry, material);
  cylinder.position.x = 8 * i;
  scene.add(cylinder);
  objArray.push(cylinder);
}

function animate(time) {
  requestAnimationFrame(animate);
  for (let obj of objArray) {
    obj.scale.y = 0.5 * Math.sin(0.002 * time + 0.02 * obj.position.x) + 1;
  }
  renderer.render(scene, camera);
}
animate();

Wie geht’s weiter?

Das war ein kurzer Einblick in die Grundlagen von three.js mit Javascript. Wenn du die beiden Projekte erfolgreich implementiert hast, kannst du kreativ werden.

Die Codebeispiele können gut als Basis zum Ausprobieren benutzt werden: Parameter verändern, Geometrien austauschen, Animation zufällig anstatt mit einer Welle usw. Oder man ersetzt die Animationen durch Physik. Mit Physik-Engines wie Cannon.js kann man realistische Animation mit Gravitation, Kollision usw. erstellen.

Zum Abschluss noch ein kurzes Fazit:

  • Three.js und WebGL ermöglichen 3D Szenen und Animation im Webbrowser
  • Man benötigt eine Szene, eine Kamera, eine Renderer, Licht und Objekte
  • Die Objekte bestehen aus einer Geometrie und dem Material. Geometrien können Würfel, Kugeln, Zylinder usw. sein. Das Material bestimmt, wie die Oberfläche davon aussieht.
  • Animationen werden mit einer Callbackfunktion realisiert: Jede Ausführung entspricht einem neuen Frame.
  • In der Animations-Funktion selbst wird die Zeit als Parameter übergeben
  • Zur Animation können sämtliche Attribute benutzt werden: Rotation, Position, Skalierung. Auch die Kamera selbst kann so animiert werden.
Bildquelle - Vielen Dank an die Ersteller:innen für dieses Bild
close