🧰Technologien für 3D im Web
<model-viewer>. Das Dateiformat glTF verbindet alle Schichten.🏗️ Die Schichten
⚖️ WebGL 1, WebGL 2 und WebGPU
| WebGL 1 | WebGL 2 | WebGPU | |
| Grundlage | OpenGL ES 2.0 | OpenGL ES 3.0 | Vulkan / Metal / Direct3D 12 |
| Spezifikation | Khronos, 2011 | Khronos, 2017 | W3C, seit 2023 in Chrome |
| Shader-Sprache | GLSL ES 1.00 | GLSL ES 3.00 | WGSL |
| Instancing | Erweiterung (ANGLE_instanced_arrays) | eingebaut | eingebaut |
| Vertex Array Objects | Erweiterung (OES_vertex_array_object) | eingebaut | Pipeline-Objekte |
| Multisample-Renderziele | nein | ja (renderbufferStorageMultisample) | ja |
| Compute-Shader | nein | nein | ja |
| Programmiermodell | globaler Zustandsautomat, jeder Aufruf sofort | wie WebGL 1 | vorab gebaute Pipelines, Befehle werden aufgezeichnet und gesammelt abgeschickt |
🔺 Rohes WebGL 2: ein Dreieck
Rund 20 Zeilen für ein einfarbiges Dreieck – ohne Matrizen, Licht oder Textur. Das Labor zeigt die ausgebaute Fassung.
1const gl = canvas.getContext("webgl2");2const vs = `#version 300 es3in vec2 aPos;4void main() { gl_Position = vec4(aPos, 0.0, 1.0); }`;5const fs = `#version 300 es6precision mediump float;7out vec4 color;8void main() { color = vec4(0.08, 0.72, 0.65, 1.0); }`;9const prog = gl.createProgram();10for (const [type, src] of [[gl.VERTEX_SHADER, vs], [gl.FRAGMENT_SHADER, fs]]) {11 const s = gl.createShader(type);12 gl.shaderSource(s, src); gl.compileShader(s); gl.attachShader(prog, s);13}14gl.linkProgram(prog); gl.useProgram(prog);15gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());16gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0.6, -0.6, -0.5, 0.6, -0.5]), gl.STATIC_DRAW);17const loc = gl.getAttribLocation(prog, "aPos");18gl.enableVertexAttribArray(loc);19gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);20gl.clearColor(0.06, 0.09, 0.16, 1); gl.clear(gl.COLOR_BUFFER_BIT);21gl.drawArrays(gl.TRIANGLES, 0, 3); // der Draw Call
🟣 WebGPU: dasselbe Dreieck
Mehr Vorbereitung, dafür weniger Überraschungen zur Laufzeit: Der komplette Zustand steckt in der Pipeline, Befehle werden gesammelt abgeschickt. Dieser Code läuft oben live, wenn dein Browser WebGPU kann.
1const adapter = await navigator.gpu.requestAdapter();2const device = await adapter.requestDevice();3const context = canvas.getContext("webgpu");4const format = navigator.gpu.getPreferredCanvasFormat();5context.configure({ device, format });67// Shader in WGSL statt GLSL – Vertex- und Fragment-Stufe in einem Modul8const module = device.createShaderModule({ code: `9 @vertex fn vs(@builtin(vertex_index) i: u32) -> @builtin(position) vec4f {10 var p = array(vec2f(0.0, 0.6), vec2f(-0.6, -0.5), vec2f(0.6, -0.5));11 return vec4f(p[i], 0.0, 1.0);12 }13 @fragment fn fs() -> @location(0) vec4f {14 return vec4f(0.08, 0.72, 0.65, 1.0);15 }` });1617// Der gesamte Zustand wird vorab in einer unveränderlichen Pipeline festgelegt18const pipeline = device.createRenderPipeline({19 layout: "auto",20 vertex: { module, entryPoint: "vs" },21 fragment: { module, entryPoint: "fs", targets: [{ format }] },22});2324// Befehle aufzeichnen und gesammelt an die GPU-Warteschlange schicken25const encoder = device.createCommandEncoder();26const pass = encoder.beginRenderPass({ colorAttachments: [{27 view: context.getCurrentTexture().createView(),28 clearValue: { r: 0.06, g: 0.09, b: 0.16, a: 1 },29 loadOp: "clear", storeOp: "store",30}] });31pass.setPipeline(pipeline);32pass.draw(3); // 3 Vertices, keine Puffer nötig33pass.end();34device.queue.submit([encoder.finish()]);
🧊 three.js
Die verbreitetste 3D-Bibliothek im Web (seit 2010, MIT-Lizenz, Ricardo Cabello „mrdoob“). Schlank, modular, riesige Beispielsammlung. Hier installiert: r186. Diese App nutzt sie für die Ferienwohnung.
1import * as THREE from "three";2import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";3import { OrbitControls } from "three/addons/controls/OrbitControls.js";45const renderer = new THREE.WebGLRenderer({ antialias: true });6document.body.appendChild(renderer.domElement);7const scene = new THREE.Scene();8const camera = new THREE.PerspectiveCamera(30, innerWidth / innerHeight, 0.1, 2000);9camera.position.set(14.5, 25.5, 19.5);10new OrbitControls(camera, renderer.domElement);11scene.add(new THREE.HemisphereLight(0xbcd3e8, 0x3b3a35, 2));12const gltf = await new GLTFLoader().loadAsync("/modelle/apartment.glb");13scene.add(gltf.scene);14renderer.setAnimationLoop(() => renderer.render(scene, camera));
🪐 Babylon.js
Vollständige Engine von Microsoft (seit 2013, Apache-2.0, in TypeScript geschrieben): Physik, GUI, Inspector, Node-Material-Editor, WebXR. Mehr „Spiele-Engine“, dafür größer. Gleiches Modell, gleiche Idee:
1import { Engine, Scene, ArcRotateCamera, HemisphericLight, SceneLoader, Vector3 } from "@babylonjs/core";2import "@babylonjs/loaders/glTF"; // registriert den glTF-Loader34const engine = new Engine(canvas, true); // true = Anti-Aliasing5const scene = new Scene(engine);6const camera = new ArcRotateCamera("kamera", Math.PI / 4, Math.PI / 3, 40, Vector3.Zero(), scene);7camera.attachControl(canvas, true); // Maus/Touch wie OrbitControls8new HemisphericLight("licht", new Vector3(0, 1, 0), scene);9await SceneLoader.AppendAsync("/modelle/", "apartment.glb", scene);10engine.runRenderLoop(() => scene.render());
🧩 <model-viewer>
Web-Komponente von Google: ein HTML-Tag, fertig. Drehen, Zoomen, Schatten, Umgebungslicht und AR (WebXR, Scene Viewer auf Android, Quick Look auf iOS) – ohne eine Zeile JavaScript. Ideal für Produktseiten.
1<!-- npm install @google/model-viewer, dann: import "@google/model-viewer"; -->2<model-viewer3 src="/modelle/apartment.glb"4 alt="Ferienwohnung in 3D"5 camera-controls6 auto-rotate7 shadow-intensity="1"8 ar>9</model-viewer>