WebGL
WebGL wird von allen modernen Browsern unterstützt und ist ein Javascript API für das Anlegen und Anzeigen von 3D-Szenen im Browser mit Hilfe der GPU (Graphical Processing Unit). WebGL wird von allen Browsern unterstützt, Ausnahmen sind alte Versionen von IE und alte Android-Versionen.
Aber WebGL (WebGL 2.0 Specification)ist ein Application Interface auf einem sehr niedrigen Niveau (nur points, lines und triangles) und es würden viele Zeilen Javascript benötigt, um auch nur das einfachste Modell in die Webseite zu setzen.
Three.js ist eine solide Open-Source Javascript Library, die den direkten Umgang mit WebGL deckelt und mit einer geradezu ausufernden Dokumentation besticht.
Ein aktives Forum hilft bei Fragen: Discourse.three.js
und Klaus Hoffmeister hat Beispiele aus dem Forum gesammelt und herausgezogen.
three.js Javascript-Library für 3D-Anwendungen
three.js von threejs.org rendert WebGL, Canvas, SVG, CSS3D und DOM und bringt Szenen, Kameras, Geometrie, 3D-Modell-Importer, Licht, Materialien, Shader, Partikel, Animationen und eine Portion Mathe mit.
Vorkenntnisse in HTML und CSS sind nicht erforderlich: Mit three.js kommt die Webseite mit einem HTML-Canvas-Element und drei Zeilen CSS aus.
Aber ohne Vorkenntnisse in einem 3D-Programm wird's sportlich: Die Begriffe, Funktionen und Elemente von 3D-Programmen sollten sitzen.
<script type="module"> import * as THREE from "https://raw.githubusercontent.com/mrdoob/three.js/dev/build/three.min.js"; …
Seit Version R106 empfiehlt three.js Javascript in der Version ES 6. Zwar können die Libraries auch klassisch einfach mit <script src=""> eingebunden werden, aber Javascript mit type="import" hat seine Vorteile.
Kamera
THREE.js hat eine perspektivische und eine orthografische Kamera in Petto. Die perspektivische Kamera agiert ähnlich wie eine Kamera in einem 3D-Programm mit vier Argumenten und ist damit die Nachbildung einer Fotokamera mit einem Zoomobjektiv.
- Field of View (FOV) Sichtwinkel, ähnlich wie die Brennweite des Kameraobjektivs
- Aspect Ratio beschreibt das Seitenverhältnis des erfassten Bildes
- Near Clipping Plane – gedachte Ebene in Sichtrichtung der Kamera, hinter der Elemente gerendert werden
- Far Clipping Plane – gedachte Ebene in Sichtrichtung der Kamera, bis zu der Elemente gerendert werden
const canvas = document.querySelector('#canvas');
const renderer = new THREE.WebGLRenderer({canvas});
const fov = 75;
const aspect = 2; // Seitenverhältnis des canvas-Elements
const near = 0.1;
const far = 5;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.z = 2;
const scene = new THREE.Scene();
Field of View (FOV) Brennweite der 3d-Kamera
Der Bildwinkel FOV der 3d-Kamera hat zwar dieselbe Wirkung wie die Brennweite des Kameraobjektivs, allerdings sind kleine Werte für FOV kleine Bildwinkel und große Werte stehen für einen großen Bildwinkel, während bei einer Fotokamera die große Brennweite einen kleinen Bildwinkel hat.
Perspektivische Kamera / Orthografische Kamera
Near Clipping Plane und Far Clipping Plane
Nur die Elemente im Bereich zwischen Near und Far Clipping Plane werden gerendert .
Field of View (FOV) ist keine Schärfentiefe, sondern eine Box oder ein Frustum (Pyramidenstumpf), innerhalb dessen der Raum gerendert wird.
Hat das Modell Löcher oder verschwinden Teile des Modells in der Ferne, dann ist das Near bzw. Far der Kamera – das Frustum – überschritten.
3D-Objekte und Mesh
3D-Objekte bestehen aus einer Geometrie – dem Polygon-Netz – und einem Oberflächen-Material.
Vor der Geometrie muss das Material feststehen: das ganze Spektrum von einfachen stumpfen farbigen Oberflächen über fertig animierte Wasseroberflächen bis hin zum Handtuch im Wind.
THREE.BoxGeometry ( 1, 1, 1 ) ist ein fertiger Würfel mit den Längen der drei Kanten. THREE.js bringt einfache geometrische Objekte schon mit: Würfel, Zylinder, Kugeln, Ringe, Kegel.
const material = new THREE.MeshPhongMaterial({color: "gold"}); const geometry = new THREE.BoxGeometry(1, 1, 1); const cube = new THREE.Mesh(geometry, material); scene.add(cube);
Wenn es über die einfachen Geometrie-Körper hinaus geht, wäre das Erstellen von 3D-Modellen mit Javascript zu aufwändig. Die Modelle werden i.d.R. in 3D-Programmen wie Blender erstellt und als Wavefront obj oder im neuen Austauschformat GLTF (GL Transmission Format) exportiert.
THREEjs importiert 3D-Modelle über Loader.
Licht
Studiofotografen und Kameramänner beim Film brauchen Lichtquellen: Ambientes Licht ist Umgebungslicht ohne Schattenbildung, daneben gerichtetes Licht für Schatten, Punkt-Lichtquellen und Strahler (Spot Light).
{ const color = 0xFFFFFF; const intensity = 1; const light = new THREE.DirectionalLight(color, intensity); light.position.set(-1, 2, 4); scene.add(light); }
CSS notiert Hexfarben mit einem Hash – #ffffff oder #000 oder #f00 (rot). In Javascript wird eine hexadezimale Zahl mit 0x anstelle von # eingeleitet.
Transformationen
mesh.position.x = -100; mesh.scale.set(2,2,2); mesh.rotation.y = Math.PI / 4; // Rotation um 45° mesh.rotation.y = THREE.Math.degToRad(45);
Wie beim Canvas 2D wird der Kreis in Radiant beschrieben.
Das komplette Script für den Würfel
<script type="module"> import * as THREE from "https://raw.githubusercontent.com/mrdoob/three.js/dev/build/three.min.js"; function main() { const canvas = document.querySelector('#canvas'); const renderer = new THREE.WebGLRenderer({canvas}); const fov = 75; const aspect = 2; // Default-Seitenverhältnis des canvas-Elements const near = 0.1; const far = 5; const camera = new THREE.PerspectiveCamera(fov, aspect, near, far); camera.position.z = 2; // Nur was in die Szene eingefügt wird, wird gerendert const scene = new THREE.Scene(); { const color = 0xFFFFFF; const intensity = 1; const light = new THREE.DirectionalLight(color, intensity); light.position.set(-1, 2, 4); scene.add(light); } const material = new THREE.MeshPhongMaterial({color: "gold"}); const geometry = new THREE.BoxGeometry(1, 1, 1); const cube = new THREE.Mesh(geometry, material); scene.add(cube); // Das 3D-Objekt mit requestAnimationFrame rotieren und rendern function render(time) { cube.rotation.x += 0.01; cube.rotation.y += 0.01; cube.rotation.z += 0.01; renderer.render(scene, camera); requestAnimationFrame(render); } requestAnimationFrame(render); } main(); </script>