3-D im Browser mit Three.js

Die dritte Dimension
Kommentare

Three.js verspricht, eine leichtgewichtige Bibliothek für die Entwicklung von 3-D-Computergrafik im Browser zu sein. Laut der Readme-Datei aus dem Three.js Repository sogar so einfach, dass es mit den Worten „for dummies“ beschrieben wird. Dieser Aussage wollen wir auf den Grund gehen.

Durch den „for dummies“-Zusatz mag unmittelbar der falsche Eindruck entstehen, dass sich Three.js lediglich für kleine und weniger anspruchsvolle Projekte eignet. Schnell gelangt man zu der Erkenntnis, dass mit der Aussage vor allem eines gemeint ist: pragmatisches, produktives und effizientes Entwickeln ohne unnötigen Overhead. Denn das Hauptaugenmerk der Bibliothek liegt neben der Kapselung sämtlicher, komplexer Prozesse in diverse Renderer vor allem darin, die Implementierung in eigene Anwendungen möglichst einfach und einheitlich zu gestalten. Das bedeutet konkret: Three.js kommt mit einem umfangreichen Repertoire daher. Angefangen mit Vektoren über Meshes bis zum kompletten Scene-Graph bietet die Bibliothek eine Menge Klassen und Helper, die für gute grafische Entwicklung maßgeblich sind. Die Computergrafik hat seit Mitte der 80er Jahre eine enorme Entwicklung durchlebt. Aus 2-D-Pixel-Grafik wurden quasi 3-D-Weltsimulationen. Die Komplexität der Methoden und Techniken im Bereich des maximal Machbaren ist stark angestiegen. An den Urprinzipien des Renderings hat sich allerdings nicht sehr viel geändert. Zwar setzt man auf komplexere Hardware, die Pre- und Post-Processing der Bilder erlaubt, aber es gilt noch immer der Grundsatz grafischer Echtzeitanimation: rechnen, zeichnen, warten, wiederholen. Diese Tatsache machen sich die Three.js-Autoren geschickt zunutze. Denn auch heute, im Web, gibt es eine Vielzahl verschiedener grafischer Technologien und APIs. Die wichtigsten sind vermutlich HTML/CSS3, SVG, Canvas und WebGL. Three.js ist zunächst API-unabhängig ausgerichtet. Wie gesagt, sind viele Helper und weitere nützliche Klassen vorhanden.

Bis auf wenige, fallspezifische Ausnahmen handhaben die übrigen Klassen vor allem eher abstrakte und mathematische Notwendigkeiten. Vergleicht man die Arbeitsteilung von Three.js mit dem Ansatz eines MVC, bestünde Three.js überwiegend aus Modellen und Helpern. Es geht darum, die Informationen zur Darstellung von 3-D-Objekten und -Szenen strukturiert erzeugen und verwalten zu können. Unabhängig von der Rendering-Technologie ist man in der Regel dazu gezwungen, genau diese Teile mühsam selbst zu entwickeln. Vektoren, Matrizen, Rotationen, Quaternionen, Primitive, Materialien. An nahezu alles wurde hier gedacht. So kann man sich beispielsweise Standardformen wie Würfel über eine Factory erzeugen lassen und dann Rotationen über ein Rotation Property auf der Instanz des Würfels vornehmen. Ebenso sind Verschiebung und Skalierung möglich. Sehr erfreulich, denn in der Regel scheitern viele Projekte daran, dass der Einstieg und der Basiscode eine steile Hürde darstellen. Mit Three.js kann man vergleichsweise schnell zur eigentlichen Umsetzung kommen.

Aufbau einer 3-D-Szene

Am Rendern eines Bilds mit Three.js sind im Groben vor allem sechs sehr wichtige Komponenten beteiligt: Scene, Camera, Geometry, Material, Mesh und Renderer.

Scene Das Scene-Objekt beschreibt einen leeren 3-D-Raum. Ähnlich einer Theaterbühne können für der Szene wichtige Gegenstände und Lichter zugewiesen werden. Das Scene-Objekt ist somit, als Datenstruktur betrachtet, der erste Knoten eines Objektbaums. Man spricht auch vom so genannten Szenegraphen. Jedes einzelne darstellbare Objekt eines zu rendernden Bilds ist zwangsläufig ein Kind-Element des Szenegraphen. Das Objekt Scene ist von Object3D abgeleitet. Die Besonderheit von Object3D ist, dass es sowohl ein Parent und mehrere Kinder haben kann. Außerdem können Raumkoordinaten und Transformationen auf Object3D angewandt werden. Demnach können, als direktes Kind einer Szene, alle Objekte hinzugefügt werden, die selbst auch von Object3D ableiten. Denn um dargestellt werden zu können, müssen Dinge/Objekte eine Position im Raum bzw. der Szene haben. Das beschreibt auch weitestgehend die Hauptaufgabe einer Szene: Man kann pro Anwendung mehrere Szenen erstellen und gegeneinander austauschen, auch offscreen. Das bedeutet, dass die Szene nicht sichtbar sein muss. Das erlaubt es unter anderem, unterschiedliche Level bereits vorzuladen.

Camera Eine Szene ohne Betrachter ist relativ bedeutungslos. Erst der Winkel, aus der ein Raum betrachtet wird, erzeugt den gewissen Eindruck. Da wir uns selbst nicht durch den virtuellen Raum bewegen können, wird hierzu eine virtuelle Kamera in die Szene gesetzt. Naiv betrachtet berichtet die Kamera, wie die Szene von ihrer eigenen Position her aussieht. Dabei spielen neben der Raumposition außerdem Parameter wie Sichtfeld, Tiefe und Seitenverhältnis eine wichtige Rolle (Listing 1).

// Öffnungswinkel der "Kameralinse"
fieldOfView = 70;
aspectRatio = canvasWidth / canvasHeight;
// Min- und Max-Distanz der Objektsichtbarkeit
near        = 1;
far         = 1000;
// Instanziiert eine leere Szene und Kamera
scene  = new THREE.Scene();
camera = new THREE.PerspectiveCamera(fieldOfView, aspectRatio, near, far);
camera.position.y = 150;
camera.position.z = 500;

Das Sichtfeld, vielerorts besser bekannt als „Field Of View“ (FOV), beschreibt den Öffnungswinkel der Kamera. Das Gesichtsfeld des Menschen variiert aufgrund unterschiedlicher anatomischer Gegebenheiten zwischen einem Winkel von 50 bis 70 Grad. So wundert es nicht, dass der Richtwert für ein halbwegs realistisch wirkendes FOV in der Computergrafik bei etwa 70 Grad liegt. Je höher der FOV-Wert, desto mehr Objekte rücken in den theoretischen „Scheinwerferkegel“, den die Kamera optisch einfangen kann. Das geht allerdings zu lasten einer sauberen Darstellung, denn je höher das FOV, desto extremer wird der Fluchtpunkt der Betrachtung ausgebildet. Ein FOV kleiner als 70 wirkt gedrängt, die Objekte wirken zudem so, als wären sie wesentlich näher an der Kamera. Neben dem Öffnungswinkel gibt es noch Werte für nah und fern. Wozu das? Wie kurz erwähnt, kann man sich das Sichtfeld der Kamera als eine Art Kegel oder eher vierseitiges Prisma vorstellen, das als abstrakter Raum in eine Szene hineinragt. Alle Objekte, die von diesem Prisma umfasst werden, gelten als „sichtbar“. Nur sichtbare Objekte müssen gezeichnet werden – das spart Rechenzeit. Während das FOV nun also den Öffnungswinkel des Prismas beschreibt, definiert die Differenz aus nah und fern (near und far) die Tiefe, also den Abstand zur Kamera mit der kleinen quadratischen Fläche (near) und den Abstand zur Kamera mit der großen quadratischen Fläche (far). Üblicherweise ist far weiter entfernt als near. Somit wächst mit jeder Einheit, mit der man sich von der Kamera entfernt, die effektive Fläche, die mit Objekten der Szene überschneiden können. Nah, weniger Kollisionsraum. Fern, mehr Kollisionsraum. Überschneidet sich ein Objekt mit den Grenzen des Kameratrapezes, so kann es stellenweise zu interessanten Effekten kommen. Ein Würfel beispielsweise, der halb in das Trapez und halb aus dem Trapez ragt, wird somit auch nur teilweise abgebildet. Je nach Position der Überscheidung kann man dann entweder in den Kubus hineinschauen oder es wirkt, als schlage der Würfel durch eine Oberfläche hindurch, sprich: Er wird vorne, hinten oder seitlich aufgeschnitten.

Renderer Der Renderer ist so ziemlich die einzige Komponente des Frameworks, die konkretes Wissen über Ausgabe- und Rendering-Logik besitzt. Wechselt man den Renderer zur Laufzeit aus, so kann man theoretisch innerhalb eines Rendering-Zyklus auf einem anderen Medium zeichnen. So kann man sich beispielsweise den Spaß machen, zwischen den Rendering-Loops von Canvas auf WebGL zu wechseln. Der einzige Umstand, der dieses Experiment erschwert, ist, dass jeder Renderer einen eigenen Kontext besitzt, auf dem gezeichnet wird. Sprich jeder Context ist einem festen HTML-Canvas-Element zugewiesen. Beide Kontexte zur gleichen Zeit auf demselben Canvas könnten zu Problemen führen. Es verdeutlicht dennoch sehr gut das Prinzip der Entkopplung. Three.js konzentriert sich nicht darauf, ausschließlich ein bestimmtes API zu bedienen. Es werden entkoppelte Renderer genutzt, um konkrete Abbilder der 3-D-Daten auf einem Medium zu zeichnen. Dabei ist es prinzipiell unerheblich, welches Medium bzw. welches API angesprochen wird.

Besonders stark und eindrucksvoll ist Three.js allerdings erst, wenn es in Kombination mit WebGL eingesetzt wird. Das mag auch an der Natur und dem Mehrwert hardwarebeschleunigter Grafik liegen. Nach außen hin kommuniziert das Projekt mittlerweile auch offen, primär eine WebGL Library zu sein. Für die Fälle, in denen leider kein WebGL eingesetzt werden kann, bietet es sich an, neben den experimentellen Renderern für CSS3 und SVG, den Canvas-Renderer als Fallback zu nutzen. Denn auch, wenn die HTML5-Revolution einen beachtlichen Wirkkreis hatte, ist WebGL-Unterstützung bei Weitem noch nicht in jedem Browser Standard. Wie der Renderer genutzt wird, ist relativ schnell erklärt. Die Berührungspunkte sind hier auf wenige Notwendigkeiten herunter zu brechen (Listing 2). Mehr wird man in der Regel mit Renderern nicht zu tun haben. Allerdings existieren gerade im WebGL-Renderer eine Menge weiterer Attribute und Optionen, die man auf dem Renderer konfigurieren kann. Via renderer.info kann man sich beispielsweise statistische Informationen zum Rendering herausreichen lassen. Diese Statistik umfasst unter anderem die Anzahl gerenderter Texturen oder Geometry-Objekte.

var canvasWidth  = window.innerWidth,
    canvasHeight = window.innerHeight,
    renderer;
// WebGL-Renderer oder Canvas-Renderer
renderer = THREE.CanvasRenderer();
// Setze die Ausgabegrösse des Canvas
renderer.setSize(canvasWidth, canvasHeight)
// Füge das Canvas-Element in den DOM hinzu
document.appendChild(renderer.domElement);
// Render ein Szenenbild aus der Sicht der Kamera auf das Canvas-Element
renderer.render(scene, camera);

Geometry Wäre Three.js ein MVC, stellte das Geometry-Objekt ein Model da. Es handelt sich um reine Datenklassen, die alle notwendigen, geometrischen Informationen zum Bau eines 3-D-Objekts enthalten. Hiervon ausgenommen sind allerdings alle konkreten Informationen wie Positionen, Rotationen oder Skalierungen. Verzerrungen des Knoten/Drahtmodells selbst können allerdings über so genannte „MorphTargets“ durchgeführt werden. Was unterscheidet ein Geometry nun also konkret von einem sichtbaren 3-D-Objekt? Es handelt sich bei Geometries quasi um Baupläne zum Erzeugen konkreter, später in der Szene sichtbarer Formen. Ein Geometry kapselt Zahlen, die als Vektoren und Strecken betrachtet eine mathematische Form beschreiben. Es enthält keine Textur und kann nicht eigenständig gerendert werden, es ist nicht sichtbar. Geometries sind die Idee von Objekten. Wer schon einmal 3-D-Objekte als Drahtmodell dargestellt gesehen hat, kommt schnell dahinter: Die Informationen zum Verbinden der Knoten und Kanten sind im Geometry enthalten. Ein Drahtmodell ist lediglich ein Weg, das mathematisch beschriebene Objekt für unser Auge sichtbar zu machen. Three.js hat von Haus aus eine Hand voll Standard-Geometries parat. Würfel, Kugel, Torus und weitere sind gut zum Prototypen einer Szene. Möchte man ein wenig mehr als „Klötzchengrafik“ darstellen, stößt man hiermit allerdings schnell an Grenzen. Hier muss man dann, wie üblich, mit eigenen Modellen arbeiten. Dazu werden so genannte „Loader“ eingesetzt. Three.js bietet einen eigenen JSONLoader an, der JSON-Objekte eines bestimmten Formats über einen URL liest und sowohl Geometry als auch entsprechende Materialobjekte daraus erzeugt. Für wesentlich gängigere Formate, wie Exporte aus Blender, Collada oder Compressed Triangle Mesh (CTM) gibt es keine Repository-Lösung. Da die Community sehr groß und hungrig ist, kann man zu diesen und anderen Formaten eine Menge Beispiele auf der offiziellen Three.js-Website finden. Wer sich ein wenig mehr Mühe gibt, findet auch im GitHub-Wiki Anleitungen, wie man beispielsweise Google-Sketchup-Modelle Three.js-tauglich exportieren kann.

Aufmacherbild: Vector illustration of 3d cubes – Illustration von iStockphoto/ Urheberrecht: v_alex

[ header = Seite 2: Material, Mesh, Lights ]

Material Materialien verhalten sich zu Geometries, wie die Zeltplane zum Gestell. Sie sind im Rendering-Prozess dafür verantwortlich, der mathematischen Repräsentation einer Form ein solides Aussehen zu verleihen. Materialien sind oftmals auch unter dem Begriff „Textur“ bekannt. In Three.js können Materialien auch Texturen, also externe Bilder enthalten. Materialien sind allerdings noch ein bisschen mehr als lediglich ein Texturen-Wrapper. In der Tat gibt es verschiedene Ausprägungen der Material-Klasse. Zunächst unterscheidet man zwischen verschiedenen Arten von Materialien. Materialien können für Mesh, Lines, Shader oder Sprites sein. Am wichtigsten sind an dieser Stelle zunächst die Mesh-Materialien. Sie werden für die solide Darstellung von 3-D-Objekten eingesetzt. Das einfachste Mesh-Material ist das MeshBasicMaterial. Ideal zur Darstellung vollfarbiger Objektflächen, Wireframe-Modelle (Zeltgestell!) oder texturierter Objekte. Texturen können als normale Flächentextur oder so genannte „Environment-Maps“ geladen werden. Environment-Maps erzeugen (eine taugliche Textur vorausgesetzt) die Illusion eines spiegelnden Objekts mit chromartiger Oberfläche – so wie eine Flipper-Kugel zum Beispiel. Wie gesagt setzt der Effekt dieser Methode auf eine Illusion. Nahestehende Objekte spiegeln sich nicht auf der Textur wider und dennoch scheint es, als würde man die Umgebung der Szene auf der Objektoberfläche wiedererkennen (Listing 3).

// Erzeugt eine Geometry und ein Material.
// Das Material soll die Farben der Geometry Faces wiederspiegeln
geometry  = new THREE.CubeGeometry(200, 200, 200),
material  = new THREE.MeshBasicMaterial({ vertexColors: THREE.FaceColors });
// Verteile zufällige Farben auf den Geometry Faces.
for(var i = 0; i < geometry.faces.length; i++) {
  geometry.faces[i].color.setHex(Math.random() * 0xffffff);
}

Das MeshBasicMaterial kann sehr vielseitig konfiguriert werden. Es lohnt sich hierzu auf jeden Fall, in der Dokumentation die genauen Parameter nachzulesen. Im gleichen Zuge ist zu empfehlen, sich die Eltern-Klasse Material genauer zu Gemüte zu führen. Alle Materialien-Klassen leiten von Material ab. Für Fälle, in denen man sich eine ausgeklügelte Beleuchtung zunächst ersparen möchte oder einfach einen schönen Effekt erzeugen will, kann man auf sehr spezielle Materialien zurückgreifen. MeshPhongMaterial und MeshLambertMaterial täuschen hierzu ein Beleuchtungsmodell vor. Gerade die Möglichkeit, andersfarbige Highlights auf dem Material zu bestimmen, kann gelegentlich zu schönen Effekten führen. Ebenfalls interessant, wenn auch wirklich nur zu Vorschau, Test oder Materialverständnis geeignet, ist das MeshNormalMaterial. Mit „Normal“ ist hier nicht das „normale Material“ gemeint. Ein Normalvektor ist ein Begriff aus der Mathematik und beschreibt einen Vektor, der orthogonal (also senkrecht) auf einem anderen mathematischen Objekt steht. In unserem Fall bezieht es sich auf eine Oberfläche eines 3-D-Objekts. Das Material ist so programmiert, dass es, je nach gradueller Ausrichtung des Normals, eine andere, dem Winkel fest zugewiesene Farbe konfiguriert. Dabei entsteht, je nach Komplexität des Objekts, eine schöne Struktur (Abb. 1). Auf Würfeln wirkt dieses Material entsprechend langweilig, da jede Seite nur eine Farbe bekommen wird.

Abb. 1: Farbgebung eines Materials

Was zunächst nach einer netten Spielerei klingt, hat wesentlich mehr Potenzial. Es verdeutlicht den Umstand, dass Materialien intelligent sein können, da sich Positionen oder andere Informationen des Objekts zu Darstellungsinformationen wandeln können. Beispielsweise Spiele, die Tiefenschärfen nutzen, brauchen Tiefeninformationen in Form einer monochromen Karte. Das lässt sich ideal mit einem Material umsetzen. Speziell für diesen Fall bringt Three.js allerdings bereits das MeshDepthMaterial mit. Mesh Sichtbare 3-D-Modelle bestehen mindestens aus einem so genannten „Mesh-Objekt“. Eine Instanz von Mesh wird zwingend mit jeweils einer Instanz von Geometry und Material im Konstruktor erzeugt. Mesh leitet, wie Scene, von Object3D ab. Sprich: Mesh wird das erste, direkt darstellbare Objekt sein, das in diesem Artikel behandelt wird. Über scene.add(meshObject) wird ein Mesh der Scene hinzugefügt. Es ist allerdings auch möglich, ein Mesh hierarchisch einem anderen Mesh hinzuzufügen: meshObject.add(anotherMesh). Das kann spannend sein, wenn man kleinere Objekthierarchien bauen möchte. Zum Beispiel für einen Avatar, der Gegenstände halten kann. Ein Mesh, das einem anderen Mesh hinzugefügt wird, existiert anschließend im Raum des Eltern-Mesh. Sprich das Kind-Mesh hat seinen Koordinatenursprung im Zentrum des Eltern-Mesh. Wenn sich das Eltern-Mesh bewegt (in Koordinate oder Winkel), bewegt sich auch das Kind-Mesh mit. Die beiden Meshs werden von der Datenstruktur her allerdings nicht zusammengelegt. Die Geometries werden nicht verschmolzen, sondern bleiben jede für sich erhalten. Hier erklärt sich nun auch der Unterschied zum THREE.Geometry. Das THREE.Mesh ist sichtbar, das THREE.Geometry nur logisch. Das THREE.Mesh ist quasi die Instanz nach Bauplan des THREE.Geometry. THREE.Mesh kann mit anderen THREE.Mesh kaskadiert werden. THREE.Geometry besteht ausschließlich aus Vektoren, die einen logischen Hohlkörper eines später darzustellenden Objekts beschreiben: rotations- und positionsneutral.

Lights Alle physikalischen Regeln, die für uns im Alltag natürlich und selbstverständlich sind, müssen in der Computergrafik erst implementiert werden. Lichter spielen dabei eine wesentliche Rolle. Arbeitet man mit verhältnismäßig simplen grafischen Systemen, braucht man sich in der Regel keine Gedanken zu machen: Hier existiert in den meisten Fällen keine Beleuchtung. Das macht bei detailliert texturierten Objekten oftmals keinen Unterschied. Wenn man aber Objekte mit vollfarbigen Flächen und ohne Beleuchtung hat, kann man die unterschiedlichen Flächen nicht mehr auseinanderhalten. Das Objekt verschwimmt zu einem einheitlichen Klumpen, der nur noch bedingt etwas von der ursprünglichen Form hat. In Sachen Beleuchtung wird einem hier sehr entgegen gekommen. Es existieren bereits verschiedene Beleuchtungsobjekte, die – wie jede Instanz von Object3D – einer Szene hinzugefügt und darin bewegt werden können. An und für sich sind Lichter in Three.js keine komplizierte Sache: Man entscheidet sich für die Art der Beleuchtung, fügt sie der Szene hinzu und positioniert die Lichter entsprechend. Was allerdings schnell frustrierend sein kann, denn im Gegensatz zu Mesh-Objekten sind Lichter unsichtbar. Positioniert man Lichter alleine über JavaScript-Code, muss man ein entsprechendes räumliches Vorstellungsvermögen aufbringen. Andernfalls kann es schnell passieren, dass man ein Licht um wenige Einheiten falsch positioniert und das Objekt nicht von dessen Wirkraum eingeschlossen wird. Denn Lichter sind keine aktive Leuchtquelle, wie man es aus der echten Welt kennt. Anders als Sonne oder Lampen haben Lichter in der 3-D-Computergrafik in der Regel weder eine sichtbare Korona, noch erzeugen sie Linsenreflexionen oder Lichtkegel. Ein positioniertes Lichtobjekt ist viel eher als eine Parameterquelle zu betrachten, die während des Rendering-Prozesses Einfluss auf die Materialien haben kann. Lichter können farblich konfiguriert werden. Lichter, die sich überschneiden, beeinflussen sich gegenseitig. Das betrifft ebenfalls die Mischung der Lichtfarben. Alles auf der Basis doch eher komplexer Berechnungen. Zu den wichtigeren Beleuchtungstypen gehören AmbientLight, PointLight und SpotLight. Ambient beleuchtet alle Objekte der Szene gleichermaßen und ohne Verlust der Intensität. Gelegentlich spricht man hier auch von globaler Beleuchtung. Licht- und Schattenspiele auf einem Objekt erzeugt man mit Instanzen von PointLight oder SpotLight. Das schließt allerdings leider keine dynamischen Schatten ein. Das PointLight ist sehr hell und intensiv im Mittelpunkt und nimmt mit der Distanz vom Mittelpunkt stetig ab. Wie ein radialer Gradient, bloß auf jeder Achse des 3-D-Raums. Das SpotLight wirft das Licht eines gerichteten Bühnenscheinwerfers. Wie erwähnt, benötigt man hierfür doch ein gewisses Vorstellungsvermögen. Für jemanden, der sich zum ersten Mal mit 3-D-Programmierung beschäftigt, stellt das eine ernstzunehmende Herausforderung dar. Zum Glück gibt es bei Three.js hierfür ebenfalls folgende Abhilfe.

Tools

Seit etwa Release r51 (aktuelles Release ist r65) liegt dem Three.js Repository ein Editor bei. Es handelt sich hierbei um einen experimentellen Szeneneditor für Szenarien inklusive Import- und Exportfunktion. Das unterscheidet Three.js unmittelbar von herkömmlichen 3-D-Libraries. Denn mit diesem Werkzeug ist man relativ einfach und schnell in der Lage, auch komplexe Szenen zu erstellen. Insbesondere nicht unmittelbar erkenntliche Dinge, wie Beleuchtung und Ausrichtungen, führen Anfänger schnell ans Frustrationslimit. Nahezu spielerisch können Objekte instanziiert, beleuchtet und mit den entsprechenden Materialien versehen werden. Das macht in der Tat Spaß und nach etwas Übung erschließt sich einem das Konzept wesentlich besser. Das spricht sehr für die Bibliothek und die damit einhergehende Philosophie. Three.js Maintainer Riccardo Cabello hat bereits auf der dotJS Conference 2012 Tools vorgestellt, die er selbst in Verbindung mit Three.js einsetzt. Hierbei wird gut illustriert, wie ein Workflow zwischen Developern und Designern, die gemeinsam an WebGL-Produktionen arbeiten, alsbald aussehen können. Der vorgestellte Timeline-basierte Editor ist ebenfalls als Work in Progress auf GitHub zu finden.

Kompatibilität

Wie immer, wenn es um die Evolution im Bereich des Web-Frontends geht, müssen wir uns der traurigen Wahrheit stellen: Wie ein Splitter im Finger müssen ältere Browser erst langsam auswachsen. Am besten irgendwann komplett aus der Systemlandschaft verschwinden. Da Microsoft jahrelang eine harte Politik bezüglich OpenGL gefahren hat, war der Einzug von WebGL im Internet Explorer lange Zeit ungewiss. Erst mit Internet Explorer 11 hat Microsoft sich erstmals für WebGL geöffnet. Das geht sogar so weit, dass Microsoft in Ihren eigenen Developer Docs von Three.js spricht. Schade ist hierbei allerdings, dass sich massive Rendering-Unterschiede zwischen WebGL in IE11 und anderen Browsern ergeben. Dabei war die Webgemeinde doch gerade erst glücklich darüber, dass Interpretationsunterschiede im DOM und CSS langsam verschwunden sind. Andere Browserhersteller hingegen haben WebGL schon wohlwollend vor einigen Jahren – und dazu auch sehr kompatibel – implementiert. Damals allerdings noch stark experimentell. Mittlerweile steht WebGL oft auch per Default zur Verfügung. Allzu viele Gedanken an ältere Browser sollte man bei Three.js nicht verschwenden, insbesondere nicht an ältere Internet-Explorer-Versionen. Für das Projekt gilt gemeinhin der Ansatz, eine Bibliothek für moderne Browser sein zu wollen. So begrüßt Three.js Maintainer Riccardo Cabello auf seiner eigenen Website Benutzer mit veralteten Browserversionen mit dem Hinweis, eine moderne Website zu haben und der Bitte um ein Browserupdate. Man könnte also zumindest für den Canvas2D-Renderer im IE8 einen weiteren Patch einspielen, der VRML simuliert (was an und für sich schon eine Notlösung darstellt). Aber nutzt man Three.js mit IE8, fällt einem schnell auf, dass bereits auf JavaScript-Ebene einige Inkompatibiliäten bestehen. Three.js macht beispielsweise durchgängig und oft Gebrauch von Object.create(), um Objekte zu erzeugen; eine Methode, die erst ab IE9 genutzt werden kann. Darüber hinaus besteht keine offizielle Dokumentation bezüglich der Abwärtskompatibilität zu anderen Browsern. Was auf jeden Fall dazu führt, die Bibliothek mit Vorsicht hinsichtlich Legacy-Browsern einzusetzen.

Fallback

Dennoch ist man spätestens an dieser Stelle dann doch froh, dass Three.js zumindest Fallbacks für verschiedene Rendering-Technologien anbietet. Zwar ist der WebGL-Renderer der mächtigste von allen, aber für viele Dinge reicht Canvas-Rendering vollkommen aus. Hier sollte, ähnlich der Graceful Degradation von Websites, bei der Planung der Anwendung darauf geachtet werden, dass die Szenarien auch mit entsprechend weniger Rechenpower vernünftig dargestellt werden können. Es ist grundsätzlich damit zu rechnen, dass Software-Rendering (CPU-beschleunigtes Zeichnen) dem Hardware-Rendering (GPU-beschleunigtes Zeichnen) vor allem in der Anzahl darstellbarer Polygone wesentlich hinterherhinkt. Aber auch sämtliche Shader-Effekte, wie man Sie aus aktuellen Computerspielen kennt, sind mit Software-Rendering nicht bzw. nur zu Fuß unter enormen Rechenaufwand möglich.

Fazit

WebGL ist auf dem aufsteigenden Ast. Davon profitiert Three.js natürlich sehr. Mit dem Ziel, eine sehr einfache Abstraktion zwischen Developer-Code und WebGL zu bieten, findet das Projekt eine Menge zufriedener Anhänger. Einer der vermutlich bekanntesten Vertreter ist der Macher von Minecraft, Markus Persson. Auch große Firmen wie Microsoft, Disney oder Google vertrauen auf Three.js. Das Projekt ist nicht kommerziell und Open Source, was es wiederum spannend für Forks und Eigenentwicklungen macht. Zwar kann nicht dieselbe Performance erwartet werden wie von einer kommerziellen Engine, aber dennoch sprechen die zahlreich verfügbaren Experimente und produktiven Projekte für einen ernstzunehmenden Einsatz. Vor allem, da sich die Three.js-Community aktuell selbst professionalisiert und es erste Ansätze spannender Tools gibt, die bei der Arbeit mit Three.js unterstützen sollen. Das macht das Projekt schnell zu mehr als einer bloßen Library. Wenn man möchte, kann man sich auf eigene und komplexe Shader einlassen – aber man wird nicht dazu gezwungen. So kann die eigene Anwendung mit der Zeit und vor allen mit den eigenen Fähigkeiten im WebGL-Bereich wachsen. Wer plant, im Bereich WebGL Projekte zu realisieren, dem sei wärmstens ans Herz gelegt, sich genauer mit Three.js zu beschäftigen.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -