Denken wir an Grafik-Engines, kommen zuerst Spiele und dann ressourcenhungrige Anwendungen in den Sinn. Wie ist es also möglich, eine Grafik-Engine und damit komplexe Applikationen im Browser zu betreiben – mobil, kompakt, performant, mit bekannten Technologien und für alle verfügbar?

Im Grunde gibt es zwei Wege. Die erste Möglichkeit bietet Web Assembly. So können bestehende Technologien wie die Unity-3D-Engine und die Unreal Engine dazu genutzt werden, Inhalte für das Web zu erstellen. Bei WebAssembly handelt es sich um speziellen Bytecode, der es ermöglicht, bestehende Programme im Browser zu nutzen und in Webseiten einzubauen. Der zweite Weg – und der Fokus dieses Artikels – bedient sich nativer Web-Technologien. Um genau zu sein, benötigt dieser Weg nur HTML und JavaScript bzw. TypeScript sowie bekannte und bereits lange existierende Web APIs. Die grundlegenden Konzepte und Methoden sind auf beiden Wegen gleich.

Es gibt mehrere Grafik-Engines für das Web. Zu den bekanntesten gehören Three.js, Babylon.js, PlayCanvas und A-Frame, um nur ein paar Beispiele zu nennen. In diesem Beitrag wird Babylon.js mit seinem Playground als Referenz und für alle Beispiele genutzt. Babylon.js ist eine Open-Source-Grafik-Engine, welche mittlerweile mit Unterstützung von Microsoft weiterentwickelt und gepflegt wird. Zu den weiteren Vorteilen gehören eine angenehme Lernkurve und die gute Dokumentation samt interaktiven Beispielen. Mit einer aktiven Community und dem engagierten Core-Entwicklerteam sind auch unerwartete Probleme und Fragen schnell geklärt.

Die zugrundeliegende Technologie WebGL wird mindestens in Version 1 von allen Browsern unterstützt. WebGL 2.0 findet ebenso eine breite Unterstützung, nur der Safari-Browser von Apple, Internet Explorer 11 und einige ältere Android-Browser scheiden hier aus. Babylon.js wählt automatisch die richtige WebGL-Version und spricht die entsprechenden APIs an. Am Ende des Beitrags wird ein fertiges Beispiel in einem Playground stehen, an dem die wichtigsten Konzepte und Lösungen erkannt und abgeleitet werden können (einmal als dunkle und einmal als helle Version).

Was ist eine Grafik-Engine und wie funktioniert sie?

Die Grafik-Engine ist als Teil einer Anwendung für die Darstellung grafischer Inhalte zuständig. Dabei ist die Art der Inhalte nicht relevant, es können einfache geometrische Formen bis hin zu komplexen Gebäuden und vielem mehr sein. Eine solche Engine bietet zahlreiche Funktionen und Möglichkeiten. Viele dieser Funktionalitäten sind bekannt oder können zumindest zugeordnet werden – sie werden selten als eigene Features erkannt. Dazu gehören: die Belichtung, die Kamera, Texturen, Sprites und Materialien. So viele Möglichkeiten es zum Einsatz gibt, so viele Funktionen bietet die Engine selbst. In diesem Artikel sehen wir uns die Funktionen, um ein 3D-Modell darzustellen und zu manipulieren, genauer an. Natürlich wird dazu unter anderem auch eine Belichtung benötigt.

Die übergeordnete Instanz (Life Cycle) – der Render Loop

Wie die meisten Programme benötigt auch eine Engine einen Life Cycle, bzw. einen Weg aufeinanderfolgende Schritte auszuführen und sicherzustellen, so dass alle nötigen Ressourcen vorhanden und initialisiert sind. Innerhalb einer Engine ist es zwingend notwendig, dass die meisten Schritte in einer festen Reihenfolge bearbeitet werden. Nur so kann ein korrektes Bild erstellt werden. Denn die Belichtung kann nicht vor der Positionierung stattfinden, andernfalls wäre eine Berechnung der Reflexionen und Schatten nicht möglich.

Der Render Loop ist eine fortwährende ausgeführte Schleife. Jeder Durchlauf generiert ein einzelnes Bild. Um eine Animation oder flüssige Bewegung darzustellen, werden im Idealfall mindestens 60 Iterationen pro Sekunde berechnet. Dabei wird eine einzelne Iteration “Frame” genannt, und diese ist auch die Performance- angebende Maßeinheit „Frames Per Second“ oder auch FPS.

Die Szene als dargestellte Instanz

Das zweite wichtige Konzept innerhalb einer Grafik-Engine ist die Szene. Eine Szene enthält alle Informationen, die nötig sind, das gewünschte Ergebnis darzustellen. Dabei enthält jedes Objekt, das sich innerhalb der Szene befindet, wiederum eine Referenz auf diese Szene. Durch dieses übergeordnete Szenenobjekt wird eine Dependency Injection wie in anderen Programmen überflüssig. Benötigt ein Objekt eine Referenz oder Informationen über ein anderes Objekt, kann diese Information oder Referenz einfach über die Szene erlangt werden.

In unserem Beispiel wird die Szene an mehreren Stellen verwendet. Neben der Initialisierung, wird jedes Objekt der Szene hinzugefügt. In diesem Beispiel erstellen wir direkt eine Kamera und die nötige Belichtung, um etwas zu sehen.

Zur Ordnung und Relation – der Szenengraph

Am einfachsten lässt sich das Konzept der sichtbaren Teile eines Sonnensystems verdeutlichen. In der Mitte steht die Sonne und rotiert, alle Planeten rotieren um die Sonne, und die Monde rotieren um ihre jeweiligen Planeten. Anstelle alle Bewegungen einzeln zu berechnen und alles zu platzieren, verschieben wir nur die jeweiligen Planeten relativ zur Sonne. Die Monde werden automatisch mitbewegt, denn ihr Ursprung ist relativ zum Planeten. Diese Relationen nennt man globale und lokale Koordinatensysteme, sie bieten viele Vorteile bei der Berechnung. Ermöglicht wird das durch eine Parent-Child-Struktur oder auch den Szenengraph.

So ist der Szenengraph eine Datenstruktur, welche es mit Model-Viewport und anderen mathematischen Transformationen ermöglicht, komplexe Positions- und Relationsberechnungen stark zu vereinfachen, zu optimieren und zu beschleunigen. In diesem Beispiel wird ein kleines System erzeugt und die einzelnen Bestandteile in eine Parent-Child Relation gebracht.

Game-Object als Basis

Nicht alles, was in einer Szene ist, wird auch dargestellt, wie z.B. Game-Objects. Sie dienen als logische Basis der meisten Inhalte in einer Engine. Mit ihnen kann man andere Objekte gruppieren oder eine übergeordnete Logik an sonst einfache Objekte anhaften. Game-Objects können beispielsweise die Logik zur Berechnung der Rotation alle ihrer Kinder untereinander enthalten und dann darauf basierend die Darstellung der Kinder beeinflussen.

Zwei Anwendungsbeispiele:

  1. Das Sonnensystem hat ein Game-Object im Root des Szenengraphen. Dieses rotiert und dreht somit das gesamte System. Alle einzelnen Bestandteile können dann zusätzlich in ihrer eigenen Geschwindigkeit rotieren.
  2. Stellt z.B. eine Lagerverwaltung fest, dass ein Regalfach zu voll wird, so können die darin befindlichen Pakete rot hervorgehoben werden.

An Ort und Stelle mit Koordinatensystemen

Zur effizienten Berechnung aller Dinge werden verschiedene Koordinatensysteme verwendet. So gibt es immer eine globale Koordinate und eine lokale Koordinate. Beginnend mit dem globalen Koordinatensystem liegt der Ursprung dieses Systems immer an der gleichen Stelle – dem globalen Nullpunkt. Alle Koordinaten im System sind relativ zu genau diesem.

Dem ergänzend bietet das lokale Koordinatensystem die Möglichkeit, eine Änderung, die relativ zum Parent-Objekt oder zu sich selbst ist, vorzunehmen. Die Berechnungen sind dieselben. In unserem Beispiel sieht man das sehr schön am Mond. Dieser wird nur um wenige Einheiten verschoben, ist jedoch ständig an der richtigen Stelle relativ zur Erde.

Die Form eines Objekts – eine Mesh

In den meisten Fällen, wenn etwas dargestellt wird, handelt es sich um eine Mesh. Es ist sozusagen der Körper einer Darstellung, sei es ein Würfel oder komplexe Formen wie ein Auto. Häufig bestehen komplexe Darstellungen aus mehreren Meshes, die auf unterschiedliche Arten und Weisen miteinander verbunden sind, so zum Beispiel gebündelt in einem Game-Object.

Die reine Mesh ist schmucklos, sie besitzt weder Textur noch Farbe. Dazu wird der Mesh mindestens ein Material und / oder eine Textur hinzugefügt.

Materialien und Texturen sind wie Kleider für Objekte

Neben einer Mesh besteht ein 3D-Objekt zumeist aus einer oder mehreren Farbinformationen, Texturen oder auch sogenannten Maps. So gibt es eine Textur, die die Farbe auf eine Mesh bringt, eine Textur für Reflexionen und die Lumineszenz oder sogar auch eine Textur für die „Rauheit” einer Oberfläche.

 

In dem Webinar 3D-Visualisierung im Web mit Babylon.js zeigt Max Schulte anhand einer Angular-Anwendung Kernaspekte sowie einen Architekturansatz, um neue Visualisierungs- und Bedienmöglichkeiten in Ihre Anwendung integrieren zu können.

Babylon.js als Web-Grafik-Engine

Grafik-Engines werden häufig mit großen Spielen und klassischen Desktop-Programmen verbunden. Jedoch lassen sich die Ergebnisse der Unity- oder Unreal-Engine auch im Browser nutzen. Inwiefern unterscheidet sich das von einer Web-Grafik-Engine wie z.B. Babylon.js?

Mit TypeScript und JavaScript Web-Native

Eines der Hauptunterschiede von Web-Grafik-Engines zu anderen ist die Nutzung der Programmiersprachen JavaScript und TypeScript. Die Engine kann direkt mit dem Browser und anderen Bestandteile von Webseiten interagieren. So viele Vorteile dies mit sich bringt – die einfache Ansprache von etwaigen Services und die Manipulation der Inhalte – so vorsichtig muss es genutzt werden. Denn eine Engine ist in sich hoch optimiert und alle Eingriffe, gewollt wie ungewollt, können zu Einbußen führen. Verbindet man die Grafik-Engine mit einem anderen Frontend-Framework, muss genau achtgegeben werden, dass die unterschiedlichen Prinzipien nicht miteinander kollidieren – das Event System und der Render Loop einer Engine darf z.B. nicht mit einem Event System (wie zone.js) interagieren.

Eine Web-Grafik-Engine beziehen und einbinden

Eine Web-Grafik-Engine kann ganz einfach, wie jedes andere Script auch, in eine Webseite eingebunden werden. Dazu wird diese als Script mit dem Script-Tag in der HTML-Datei vermerkt, sodass der Browser es dann zur richtigen Zeit lädt und ausführt.

Sobald die 3D-Anwendung über eine einfache Szene oder kleines Projekt hinausgeht, empfiehlt es sich jedoch, die Pakete lokal zu installieren und in einer JavaScript/TypeScript-typischen Struktur zu arbeiten.

Der Babylon.js-Playground

Sieht man sich Tools wie Stackblitz und CodePen an, wird schnell klar, wie sie Entwicklern helfen, moderne Applikationen besser zu verstehen, Konzepte schnell zu testen und Ideen mit anderen zu teilen. So ein Tool gibt es auch für Babylon.js – den Playground. Alle Beispiele in diesem Artikel sind im Babylon.js-Playground verfasst. Je nachdem, welche Installation von Babylon.js genutzt wird, sind Anpassungen nötig. Der Playground stellt Babylon per globaler Variable bereit. So kann man mit `BABYLON` auf alle Funktionen und Objekte zugreifen.

Eine Einführung in Grafik-Engines für Webentwickler – Fazit

Seit einigen Jahren ist klar zu erkennen, dass immer mehr Anwendungen und Szenarien im Browser gelöst werden können. Klassische Business-Anwendungen werden immer mehr durch Web-basierte Lösungen ergänzt oder gar komplett ersetzt. Die Browserhersteller stellen immer neue APIs bereit, die Frameworks reifen, und die Plattformen werden leistungsfähiger – dieser Trend ist auch auf Web-Grafik-Engines übertragbar. Die Frameworks werden besser und bieten einen einfachen Weg, Anwendungen mit bekannten Mitteln einer breiten Masse bereitzustellen – und das auf allen Plattformen.

Die jüngsten Entwicklungen zeigen genau dies: WebGPU ist auf dem Vormarsch, und als Nachfolger von WebGL 2.0 bietet es direkteren Zugriff auf die Hardwarebeschleunigung und bringt einen immensen Leistungsschub. Die Spezifikation ist noch jung, wird jedoch schon von vielen Bibliotheken genutzt und implementiert. Zuletzt stellt Babylon.js eine Playground-Variante mit WebGPU bereit. Auch Apple implementiert immer mehr APIs in den Safari-Browser, die neueste Entwicklung ist WebXR. Dies öffnet den Zugang zu Virtual Reality und Augmented Reality auf Apples Browser-Plattformen. Die Aussichten für Web-getriebene Grafikanwendungen sind also rosig.

In einem zweiten Teil zum Thema 3D-Anwendungen im Web werde ich zeigen, wie sich unser Sonnensystem-Beispiel in eine Angular-Business-Web-App einbauen lässt und wie beide Anwendungsteile reibungslos miteinander interagieren können und sich ergänzen.

Max Schulte

Große Auswahl an günstigen Domain-Endungen – schon ab 0,08 € /Monat
Jetzt Domain-Check starten