WebGL Grundlagen 1 – Dreiecke und Quadrate.
Willkommen zum ersten Teil unserer WebGL Grundlagen. In diesem Teil werden wir ihnen aufzeigen, wie Sie ein Dreieck und ein Quadrat auf einer Website gestalten können. Sollten Sie diesen Teil verstehen, wird der Rest nicht mehr so schwer sein.
Ein wichtiger Hinweis: Dieser Teil richtet sich an Personen mit fortgeschrittenen Programmierkenntnissen, aber ohne wirkliche Erfahrung mit 3D-Grafiken. Sie werden ein gutes Verständnis für den Code mitbringen und es zum Laufen bringen, so dass Sie so schnell wie möglich mit der Erstellung einer eigenen Website in 3D beginnen können.
Es existieren zwei verschiedene Möglichkeiten, den Code für dieses Beispiel zu erhalten. In den Browsereinstellungen mit „View Source“, während Sie sich die Live-Version ansehen oder wenn Sie GitHub verwenden, können Sie es aus dem Repository kopieren. Unabhängig davon für welchen Weg Sie sich entscheiden, sollten Sie ihren bevorzugten Texteditor herunterladen und Sie den Code genau ansehen. Auf dem ersten Blick ist alles etwas ziemlich entmutigend, selbst wenn man schon erste Erfahrungen mit OpenGL hat. Zu Beginn definieren wir ein paar Shader, die im Allgemeinen als relativ fortgeschritten gelten. Sie sollten aber nicht verzweifeln, da es viel einfacher ist als es auf dem ersten Moment aussieht.
Wie viele andere Programme auch beginnt auch diese WebGL-Seite mit der Definition einer Reihe von untergeordneten Funktionen, die vom High-Level-Code unten verwendet werden. Um es zu erklären, werde ich unten anfangen und mich nach oben arbeiten. Wenn Sie also den Code durchgehen, springen Sie nach unten.
Sie werden den folgenden HTML-Code sehen:
Dies ist der gesamte body der Seite – alles andere ist in JavaScript. Offensichtlich könnten wir mehr normales HTML in die body-Tags und unser WebGL-Bild in eine normale Website einbauen. Für diese einfache Demo haben wir allerdings nur Links zurück zu diesem Blog-Post und dem canvas-Tag, in der sich die 3D-Grafiken befinden. Canvases sind noch relativ neu für HTML5 – so unterstützt es neue Arten von JavaScript-gezeichneten Elementen in Webseiten, sowohl 2D als auch 3D. Wir spezifizieren nichts weiter als die einfachen Layout-Eigenschaften der Canvases in ihrem Tag und überlassen stattdessen den gesamten WebGL-Setup-Code einer JavaScript-Funktion mit der Bezeichnung webglstart, die Sie sehen werden solbald die Seite geladen wurde.
Scrollen wir nun zu dieser Funktion und schauen wie uns diese an:
Es ruft Funktionen auf, um WebGL und die Shader zu initialisieren, indem es das Canvas-Element auf dem wir unsere 3D-Grafiken zeichnen möchten in das erste Element übergibt. Anschließend initialisiert es einige Puffer mit initBuffern. Puffer sind Dinge, welche die Details des Dreiecks und des Quadrats enthalten, die wir zeichnen werden – mehr darüber aber später.
Als nächstes führt es einige grundlegende WebGL-Einstellungen durch, mit denen wir die Canvases leeren und schwarz malen. An dieser Stelle sollten wir auch eine tiefere Prüfung vornehmen. Diese Schritte werden durch Aufrufe von Methoden auf einem gl-Objekt implementiert – wir werden sehen, wie das später initialisiert wird. Schließlich ruft es die Funktion drawScene auf, die das Quadrat mit Hilfe von Puffer zeichnet.
Wir werden später noch einmal auf initGL und initShaders zurückkommen, um zu verstehen wie die Seite funktioniert, aber zuerst werfen wir einen Blick auf initBuffers and drawScene.
Wir beginnen zunächst Schritt für Schritt mit den initBuffers:
Wir deklarieren zwei globale Variablen, um die Puffer zu halten.
Wir erstellen einen Puffer für die Eckpunkte des Dreiecks. Eckpunkte sind die Punkte im 3D-Raum, welche die Formen definieren, die wir zeichnen. Für unser Dreieck werden wir drei davon haben. Dieser Puffer ist eigentlich ein bisschen Speicher auf der Grafikkarte. Indem wir die Vertex-Positionen einmal in unserem Initialisierungscode auf die Karte setzen und WebGL mitteilen, dass es die gewünschten Inhalte zeichnen soll, kann der Code wirklich effizient gestaltet werden.
Dies gilt insbesondere dann, wenn wir mit der Animation der 3D-Szene beginnen und das Objekt zigmal pro Sekunde zeichnen wollen, um es zu bewegen. Gerade bei sehr kompexen Modellen mit mehreren Tausend Verticles macht es Sinn, so vorzugehen, wie oben beschrieben.
Diese Zeile teilt WebGL mit, dass alle nachfolgenden auf Puffer wirkende Operationen, die von uns angegebene verwenden sollten. Es gibt immer dieses Konzept eines aktuellen Array-Puffers und die Funktionen wirken darauf, anstatt ihnen zu erlauben, den Array-Puffer anzugeben, mit dem Sie arbeiten möchten. Dahinter stecken mit Sicherheit gute Gründe für die Performance.
Als Nächstes definieren wir unsere Vertex-Positionen als JavaScript-Liste. Man kann sehen, dass sie sich an den Punkten eines gleichschenkligen Dreieck befinden, dessen Mittelpunkt bei (0,0,0,0) liegt.
Jetzt erstellen wir ein Float32Array-Objekt basierend auf unserer JavaScript-Liste und weisen WebGL an, es zu verwenden. Im konkreten Anwendungfall handelt es sich dabei natürlich um unseren triangleVertexPositionBuffer. Wir werden in einem späteren Abschnitt mehr über Float32Arrays sprechen, aber im Moment müssen Sie nur wissen, dass diese eine Möglichkeit darstellen eine JavaScript-Liste in etwas zu verwandeln, dass wir an WebGL übergeben können, um die Puffer zu füllen.
Als letztes weisen wir dem Puffer noch zwei Eigenschaften zu. Diese werden später sehr nützlich sein. Eine nette Sache über JavaScript ist, dass ein Objekt nicht explizit eine bestimmte Eigenschaft unterstützen muss, damit Sie es darauf setzen können. Obwohl das Buffer-Objekt bisher keine itemSize- und numItems-Eigenschaften hatte, führt es nun die gewünschten Eigenschaften aus. Dieser 9-Elemente-Puffer repräsentiert drei separate Vertex-Positionen, von denen jede aus drei Zahlen besteht (itemSize).
Jetzt haben wir den Puffer über das Dreieck komplett eingerichtet, so dass es auf dem Quadrat liegt:
All das sollte ziemlich offensichtlich sein – das Quadrat hat vier Vertex-Positionen statt 3 und so ist das Array größer und die NumItems sind unterschiedlich.
Damit haben wir nun die Scheitelpunkte unserer beiden Objekte bis zur Grafikkarte verschoben. Betrachten wir nun Schritt für Schritt drawScene:
Der erste Schritt ist, WebGL ein wenig über die Größe der Canvases mit Hilfe der Viewport-Funktion zu informieren. Wir werden in späteren Abschnitten wieder darauf zurückkommen. Fürs erste müssen Sie nur wissen, dass die Funktion mit der Größe des Canvas aufgerufen werden muss, bevor Sie mit dem Zeichnen beginnen. Als nächstes räumen wir das Canvas auf, um Sie für die Zeichnung vorzubereiten:
Und dann…
Hier definieren wir die Perspektive, mit der wir die Szene betrachten wollen. Standardmäßig zeichnet WebGL Objekte, die nahe bei der gleichen Größe liegen wie Dinge, die weit entfernt sind. Um Objekte, die weit entfernt sind kleiner aussehen zu lassen, müssen WebGL Informationen über die Perspektive mitgeteilt werden. Für diese Szene definieren wir ein vertikales Sichtfeld (45 Grad). Zudem sollen keine Objekte zu sehen sein, die näher als 0,1 Einheiten zu unserem Standpunkt sind oder weiter als 100 Einheiten entfernt sind.
Wie Sie sehen können, verwendet dieses perspektivische Material eine Funktion aus einem Modul mit der Bezeichnung mat4 und eine Variable namens pMatrix. Mehr Informationen dazu folgen später. Aber es sollte an dieser Stelle klar sein, wie man Sie nutzen kann ohne die Details zu kennen.
Da wir nun die Eigenschaften der Perspektive definiert haben, können wir nun mit dem Zeichnen von Objekten fortfahren.
Der erste Schritt ist das Verschieben in die Mitte der 3D-Szene. Wenn Sie in OpenGL eine Szene zeichnen, teilen Sie WebGL mit, dass jedes Objekt mit einer aktuellen Position und einer aktuellen Rotation zeichnen soll. So können Sie z.B. bestimmen, dass sich das Objekt 20 Einheiten vorwärts bewegen oder um 32 Grad drehen soll. Dies ist nützlich, weil Sie den Code „Draw the Robot“ in einer Funktion kapseln können und anschließend den Roboter einfach umherbewegen können, indem Sie einfach das Verschieben/Drehen-Material ändern, welches Sie vor dem Aufruf der Funktion definiert haben.
Die aktuelle Position und Rotation werden beide in einer Matrix gehalten. Wie Sie schon mit Sicherheit in der Schule gelernt haben, können Matritzen Übersetzungen, Rotationen und andere geometrische Transformationen darstellen. Um eine beliebige Anzahl von 3D-Transformationen im 3D-Raum darzustellen, können Sie eine einzelne 4×4-Matrix verwenden. Sie beginnen mit der Identitätsmatrix und multiplizieren Sie dann mit der Matrix, die ihre erste Transformation darstellt anschließend mit der Matrix, die ihre zweite Transformation darstellt und so weiter. Die kombinierte Matrix stellt alle ihre Transformationen in einer einzigen dar. Die Matrix, die wir verwenden, um den aktuellen Status zu repräsentieren wird als Model-View-Matrix bezeichnet. Die Variable myMatrix enthält unsere Model-View-Matrix und die mat4.identity-Funktion, die wir soeben aufgerufen haben, setzt Sie auf die Identitätsmatrix, so dass wir bereit sind mit der Multiplikation von Übersetzungen und Rotationen zu beginnen. Oder anders ausgedrückt: Wir befinden uns wieder beim Ursprungspunkt um mit dem Zeichnen unserer 3D-Welt zu beginnen.
Scharfsinnige Leser werden bemerkt haben, dass ich zu Beginn dieser Diskussion über Matritzen in OpenGL gesagt habe und nicht in WebGL. Dies liegt daran, dass WebGL dieses Material nicht in die Grafikbibliothek integriert hat. Stattdessen verwenden wir eine Matrixbibliothek von Drittanbietern und einige raffinierte WebGL-Tricks, um den gleichen Effekt zu erzielen. Mehr dazu erfahren Sie später.
Nun zu dem Code, welcher das Dreieck auf der linken Seite in unserem Canvas zeichnet:
Nachdem wir uns in die Mitte unseres 3D-Raums bewegt haben, indem wir myMatrix auf die Identitätsmatrix gesetzt haben, beginnen wir mit dem Dreieck, indem wir 1,5 Einheiten nach links und sieben Einheiten in die Szene verschieben.
Der nächste Schritt ist mit dem Zeichnen zu beginnen.
Wir müssen nun gl.bindBuffer aufrufen, um einen aktuellen Puffer anzugeben und dann den Code aufrufen, der darauf operiert. Hier wählen wir unseren triangleVertexPositionBuffer aus und teilen WebGL mit, dass die darin enthaltenen Werte für Vertex-Positionen verwendet werden sollen. Ich werde ein wenig mehr darüber erklären, wie das später funktioniert. Im Anwendungsbeispiel verwenden wir die itemSize-Eigenschaft um WebGL mitzuteilen, dass jedes Element im Puffer genau drei Zahlen lang ist.
Noch ein Schritt und wir sind durch:
Dies veranlasst WebGL unsere aktuelle Model-View-Matrix zu berücksichtigen. Dies ist erforderlich, da all diese Matrix-Zeugnisse nicht in WebGL integriert sind. Mit der Funktion setMatrixUniforms verschieben wir die Model-View-Matrix auf die Grafikkarte.
Sobald dies geschehen ist hat WebGL ein Array von Zahlen, von denen es weiß, dass Sie als Vertex-Positionen behandelt werden sollten und es kennt unsere Matrizen. Der nächste Schritt teilt WebGL mit, was er mit ihnen machen soll:
Durch die Funktion, wird das Array der Eckpunkte gezeichnet, die zuvor als Dreiecke gezeichnet worden sind, beginnend mit dem Punkt 0 im Array und steigend bis zum numItemsth-Element.
Sobald dies geschehen ist, wird WebGL unser Dreieck gezeichnet haben. Zeichnen Sie als Nächstes das Quadrat:
Wir beginnen damit durch das Verschieben unserer Model-View-Matrix um drei Einheiten nach rechts. Denken Sie daran, dass wir zur Zeit 1,5 nach links und 7 vom Bildschirm entfernt sind, so dass wir 1,5 nach rechts und 7 nach rechts gehen.
Also teilen wir WebGL mit, dass es den Puffer unseres Quadrats für seine Vertex-Positionen verwenden soll…
Wir schieben die Model-View- und Projektionsmatrizen wieder hinüber, was bedeutet, dass wurd es endlich schaffen könnten.
}
Wenn Sie nun schon so weit gekommen sind, sollten Sie bereit sein mit dem Experimentieren zu beginnen. Kopieren Sie den Code in eine lokale Datei, entweder von GitHub oder direkt von der Live-Version. Sofern Sie Letzteres tun benötigen Sie index.html und glMatrix-0.9.5.5.min.js. Führen Sie es lokal aus, um sicherstellen zu können, dass es funktioniert. Anschließend sollten Sie versuchen einige der oberen Scheitelpunkt zu ändern. Insbesondere ist die Szene jetzt ziemlich. Versuchen Sie die Z-Werte für das Quadrat auf 2 oder 3 zu ändern und Sie werden sehen, dass es größer oder kleiner wird, wenn es sich vorwärts oder rückwärts bewegt. Oder versuchen Sie nur ein oder zwei davon zu ändern und beobachten Sie, wie Sie sich perspektivisch verzerren.
Nun werfen wir einen Blick auf die Support-Funktionen, die den gesamten Code, den wir gerade überarbeitet haben erst möglich gemacht haben. Wie ich bereits gesagt habe, wenn Sie die Details ignorieren und einfach die Support-Funktionen nutzen, die über initBuffers in der Seite stehen, kopieren und einfügen, können Sie wahrscheinlich damit durchkommen und interessante WebGL-Seiten erstellen. Aber keine der Details sind schwer zu verstehen und wenn man versteht wie dieses Zeug funktioniert, wird man wahrscheinlich später einen besseren WebGL-Code schreiben.
Wir werden erst einmal die langweiligen Funktionen aus dem Weg räumen. Die erste welche von webglStart aufgerufen wirdm das ist initGL. Es befindet sich ganz oben auf der Webseite und hier ist eine Kopie als Referenz.
Das ist ganz einfach. Wie Sie vielleicht schon bemerkt haben, beziehen sich die initBuffers und drawScene Funktionen häufig auf ein Objekt mit der Bezeichnung gl, dass sich eindeutig auf eine Art Kern WebGL bezieht. Diese Funktion holt das Objekt, welches als WebGL-Kontext bezeichnet wird und fragt den Canvas, welche für den Kontext definiert wurde unter Verwendung eines Standardkontextnamens ab. Sobald wir den Kontext haben, benutzen wir wieder die Bereitschaft von JavaScript und zu erlauben jede Eigenschaft auf jedes Objekt zu setzen, um darauf die Breite und Höhe des Canvas zu speichern, auf die es sich bezieht. Wir möchten den Code verwenden, der das Ansichtsfenster und die Perspektive am Anfang von drawScene einrichtet. Sobald das erledigt ist, wird unser GL-Kontext eingerichtet.
Nach dem Aufruf von initGL rief WebGLStart initShaders auf. Wir kommen später noch einmal darauf zurück, denn zuerst sollten wir uns unsere Model-View-Matrix und die Projektionsmatrix ansehen, die wir bereits erwähnt haben. Hier ist der Code:
Also definieren wir eine Variable mit der Bezeichnung myMatrix, um die Model-View-Matrix zu halten und eine Variable mit der Bezeichnung für die Projektionsmatrix und setzen Sie anschließend auf leere (all-zero) Matrizen, um damit anzufangen. Es lohnt sich an dieser Stelle, hier ein wenig mehr über die Projektionsmatrix zu wissen. Wie Sie mit Sicherheit erinnern werden, haben wir die glMatrix-Funktion mat4.perspective auf diese Variable angewendet, um unsere Perspektive gleich zu Beginn auf drawScene zu richten. Dies liegt daran, dass WebGL die Perspektive nicht direkt unterstützt, genauso wenig wie es eine Model-View-Matrix direkt unterstützt. Aber genauso wie der Prozess des Bewegens und Drehens von Dingen, die in der Model-View-Matrix gekapselt sind, können damit auch Objekte, die dicht oder weit auseinander liegen optisch ansprechend gestalten werden. Letzteres kann durch die Projektionsmatrix erreicht werden. Die Funktion mat4.perspective mit ihrem Seitenverhältnis ind Sichtfeld füllt die Matrix mit den Werten, die uns die gewünschte Perspektive geben.
Kümmern wir uns anschließend um den Hintergrund:
Was ist eigentlich ein Shader? Nun, irgendwann in der Geschichte der 3D-Grafik mögen Sie wohl das gewesen sein, wie Sie auch klingen. Code-Bits, die dem System mitteilen, wie es Teile einer Szene schattieren oder färben soll, bevor Sie gezeichnet wird. Im Laufe der Zeit haben Sie jedoch an Umfang zugenommen, so dass Sie nun besser als Code-Bits definiert werden können, die absolut alles tun können, was Sie sollen, bevor Sie gezeichnet werden. Und das ist eigentlich ziemlich nützlich, denn Sie laufen auf der Grafikkarte, also machen Sie das, was Sie wirklich schnell machen und die Art von Transformationen, die Sie machen können, werden sogar in einfachen Beispielen wie hier praktisch sein.
Der Grund, weshalb wir Shader in einem einfachen WebGL-Beispiel einführen, liegt darin, dass wir Sie benutzen, um das WebGL-System, das hoffentlich auf der Grafikkarte läuft, dazu zu bringen, unsere Model-View-Matrix und unsere Projektionsmatrix auf unsere Szene anzuwenden ohne dass wir uns um jeden Punkt und jeden Scheitelpunkt in langsamen JavaScript bewegen müssen. Das ist unglaublich nützlich und den zusätzlichen Aufwand wert.
Wie Sie sich erinnern werden, rief webGLStart initShaders auf, also lassen Sie uns das Schritt für Schritt durchgehen:
Wie Sie sehen, verwendet es eine Funktion mit der Bezeichnung getShader, um zwei Dinge zu erreichen. Ein Fragment-Shader und einen Vertex-Shader werden beide an ein WebGL Thing angehängt, die als Programm bezeichnet werden. Ein Programm ist ein bisschen Code, der auf der WebGL-Seite des Systems lebt. Man kann es als eine Möglichkeit betrachten, etwas anzugeben, das auf der Grafikkarte ausgeführt werden kann. Wie zu erwarten ist, können Sie damit eine Reihe von Shader assoziieren, von denen jeder als Code-Schnipsel in diesem Programm zu sehen ist. Speziell kann jedes Programm einen Fragment- und einen Vertex-Shader enthalten. Wir werden Sie uns in Kürze ansehen.
Nachdem die Funktion das Programm eingerichtet und die Shader angehängt hat, erhält Sie eine Referenz auf ein Attribut, dass Sie in einem neuen Feld auf dem Programmobjekt vertexPositionAttribute speichert. Wieder einmal nutzen wir die Bereitschaft von JavaScript, jedes Feld auf ein beliebiges Objekt zu setzen. Programmobjekte haben standardmäßig kein vertexPositionAttribut-Feld, aber es ist bequemer für den Anwender die beiden Werte zusammenzuführen, also machen wir das Attribut einfach zu einem neuen Feld des Programms.
Wofür ist das vertexPositionAttribut? Wie Sie sich vielleicht erinnern werden, haben wir es in drawScene verwendet. Wenn Sie nun auf den Code zurückblicken, der die Vertex-Positionen des Dreiecks aus dem entsprechenden Puffer setzt, werden Sie sehen, dass die Dinge, die wir gemacht haben den Puffer mit diesem Attribut assoziiert haben. Sie werden sehen, was das in einem Moment bedeutet. Für den Moment lassen Sie uns nur beachten, dass wir auch gl.enableVertexAttribArray verwenden, um WebGL mitzuteilen, dass wir Werte für das Attribut mit Hilfe eines Arrays bereitstellen wollen.
Das Letzte was initShader tun um zwei weitere Werte aus dem Programm zu erhalten ist die Speicherorte von zwei Dingen als einheitliche Variable zu bezeichnen. Wir werden Sie bald antreffen. Für den Moment sollten Sie nur beachten, dass wir Sie wie das Attribut auf dem Programmobjekt speichern.
Nun werfen wir einen Blick auf getShader:
Dies ist eine weitere dieser Funktionen, die viel einfacher ist, als Sie aussieht. Alles, was wir hier tun, ist nach einem Element in unserer HTML-Seite zu suchen. Die Funktion hat eine ID, die mit einem Parameter übereinstimmt, die übergeben wird. Zudem wird der Inhalt herausgezogen und ein Fragment- oder Vertex-Shader basierend auf seinem Typ erstellt. Anschließend wird es an WebGL weitergeleitet, um es in ein Formular zu kompilieren, das auf der Grafikkarte ausgeführt werden kann.
Der Code behandelt dann alle Fehler und das wars dann schon. Natürlich könnten wir Shader einfach als Strings in unserem JavaScript-Code definieren und uns nicht damit herumschlagen, Sie aus dem HTML zu extrahieren – aber auf diese Weise machen wir Sie viel leichter lesbar, weil Sie aks Skripte in der Website definiert sind.
Nachdem wir das gesehen haben, sollten wir einen Blick auf den Code der Shader werfen:
Das erste, woran man sich erinnern sollte ist, dass Sie nicht in JavaScript geschrieben sind, obwohl die Herkunft der Sprache eindeutig ähnlich ist. Tatsächlich sind Sie in einer speziellen Shader-Sprache GLSL geschrieben, die C viel zu verdanken hat.
Der Fragment-Shader tut so ziemlich gar nichts. Er hat lediglich ein wenig obligatorischen Boilerplate-Code, um der Grafikkarte mitzuteilen, wie präzise wir Sie mit Fließkommazahlen haben wollen.
Der zweite Shader ist ein wenig interessanter. Es handelt sich um einen Vertex-Shader – was bedeutet, dass es ein bisschen Grafikkartencode ist, der so ziemlich alles kann, was er mit einem Vertex machen kann. In Verbindung damit hat es zwei einheitliche Variablen, die uMVMatrix und uPMatrix genannt werden. Uniformvariablen sind nützlich, weil Sie von außerhalb des Shaders zugänglich sind – in der Tat, von außerhalb des Programms, welches Sie enthält, wie Sie sich wahrscheinlich daran erinnern können, wann wir ihre Position in initShaders extrahiert haben und aus dem Code, den wir uns als nächstes ansehen werden, wo wir Sie auf die Werte der Modellansicht und der Projektionsmatrizen setzen. Sie können sich das Programm des Shaders als Objekt und die einheitlichen Variablen als Felder vorstellen.
Jetzt wird der Shader für jeden Vertex aufgerufen und der Vertex wird dem Shader-Code aks aVertexPosition übergeben, dank der Verwendung des vertexPositionAttributes in der DrawScenem wenn wir das Attribut mit dem Puffer assoziieren. Das Winzige bisschen Code in der Hauptroutine des Shaders multipliziert einfach die Position des Scheitelpunktes mit der Modellansicht und den Projektionsmatrizen und drückt durch das Ergebnis als Endposition des Scheitelpunktes aus.
So nannte webGLStart initShaders, die getShader benutzen, um das Fragment und die Vertex-Shader aus Skripten in der Website zu laden, so dass Sie kompiliert und an WebGL übergeben werden konnten und später beim Rendern unserer 3D-Szene verwendet wurden.
Nach all dem ist der einzig verbleibende unerklärliche Code setMatrixUniforms, welcher leicht zu verstehen ist, sobald man alles oben genannte weiß.
Mit den References auf die Uniforms, die unsere Projektionsmatrix und unsere Model-View-Matrix repräsentieren, die wir in initShaders zurückbekommen haben, senden wir WebGL die Werte aus unseren JavaScript-Matrizen.
Das war der erste Teil zu den Grundlagen von WebGL. Es werden weitere folgen.