<iso>

@schlagwort:3D im Web

@rubrik:praxis

@arbeitstitel:web_gl_tut_2

@d:WebGL-Tutorial, Teil 2: Texturen, Animation und ModelView-Matrix

@t:Leben ins Web                                                  PS: Wäre ok, gefällt mir aber nicht so richtig. Vielleicht "Bewegung in die Tiefe"  "3D in Aktion" ?

@a:Peter Strohm

@v:Puristen mögen dagegen sein -- Fakt ist, dass                   
interaktive Multimedianawendungen überall im Web
zu finden sind. Ein Beispiel zeigt, wie man mit
HTML5 und dem neuen Standard WebGL
3D-Darstellungen animieren kann.

@initial:Mit der Veröffentlichung der Version 1.0
des WebGL-Standards und kurz darauf dem Erscheinen
der Browserversionen Chrome 9.0 und Firefox 4.0,
die WebGL unterstützen, steht der Verwendung
interaktiver 3D-Grafik ohne zusätzliche Plug-ins
innerhalb von Webseiten nichts mehr im Wege. Bis
auf Microsofts Internet Explorer sollen alle
großen Browser in naher Zukunft WebGL-fähig sein.

@$:Der erste Teil dieses Tutorials hat die
Grundlagen der Initialisierung einer
WebGL-Umgebung bis hin zur ersten Geometrie
erläutert. Der Rahmen von WebGL-Inhalten dürfte
häufig ähnlich bis gleich aufgebaut sein. Eine
Anwendung muss immer den WebGL-Context aus dem
Canvas-Objekt erfragen und ein
WebGL-Program-Objekt anlegen. Darüber hinaus muss
der Entwickler die Shader erstellen, kompilieren
und mit dem Linker einbinden.

Für die ernsthafte Entwicklung von WebGL-Inhalten
ist das Verständnis für diese "immer gleiche"
Initialisierung unverzichtbar. Dieser Artikel ist
dennoch so gestaltet, dass der Leser die
behandelten Themen "perspektivische Projektion,                    PS: perpektivische Projektion war schon im ersten Teil; stattdessen kann hier "Objekttransformation" oder "Model-View-Matrix" stehen.
Texturen und Animation" ohne Details des
WebGL-Rahmens nachvollziehen kann, da die
WebGL-Initialisierung in <I>.js<I>-Dateien
ausgelagert ist.

Für die Initialisierung empfiehlt das Wiki der
Khronos-WebGL-Seite die Verwendung von
<I>webgl-utils.js<I> (siehe "Onlinequellen" [e]
und <I>iX<I>-Link), einer winzigen, von Google
entwickelten Bibliothek. Die zwei Funktionen in
dieser Minibibliothek machen die Initialisierung
des WebGL-Context und die Basisfunktionen für die
Animation browserunabhängig und übernehmen die
rudimentäre Fehlerbehandlung.

Darüber hinaus wird der WebGL-Context (<I>gl<I>)
zusammen mit weiteren projektweiten Variablen im
globalen Objekt <I>meinWebGLObjekt<I> vom Typ der
selbsterstellten Klasse <I>WebGLObjekt<I>
zusammengefasst. Im Sinne der Objektorientierung
enthält diese Klasse auch die Funktionen
<I>init()<I>, <I>draw()<I> und
<I>aktualisiereAttribUniformLocations()<I>.

Weitgehend entspricht die <I>init()<I>-Funktion
der Initialisierung, wie sie der erste Artikel                            
vorgestellt hat [1]. Lediglich der WebGL-Kontext des                      
Canvas-Objekts wird über die erwähnte
Bibliotheksfunktion <I>WebGLUtils.setupWebGL<I>
initialisiert (Zeile 64).

Die Verknüpfung zwischen Shadern und JavaScript
erfolgt über die jeweiligen Namen der
Attribute/Uniforms in den Shadern sowie über die
Funktionen <I>getAttribLocation<I> (Zeile 23) und
<I>getUniformLocation<I> (Zeile 22), die in der
Funktion <I>aktualisiereAttribUniformLocations<I>
(Zeile 19) zusammengefasst sind.

@z:Freie Hilfe bei den Matrizen

@$:Bei der Erzeugung eines Dreiecks im ersten
Tutorial wurden die Raumkoordinaten so gewählt,
dass das Dreieck mittig vor der virtuellen Kamera                        PS: Plural. Dreiecke...liegen
liegt. Sobald es um mehr geht als ein einzelnes
Dreieck, ist dieses Vorgehen schnell nicht mehr
handhabbar. Üblicherweise beschreibt man jedes
Objekt zunächst in seinem eigenen
Koordinatensystem und transformiert es danach
mittels Translations- und Rotationsmatrizen an
die finale Position. Da die hierfür nötige
Vektoralgebra allein Bücher füllen kann, geht das
Tutorial nicht weiter darauf ein, sondern
beschränkt sich auf ihre Anwendung.

Anders als die WebGL-Shader kennt JavaScript
Vektoren und Matrizen nicht von Haus aus, daher
kommt hier eine frei verfügbare
JavaScript-Bibliothek zum Einsatz. Die am
weitesten entwickelte Vektor/Matrix-Bibliothek in
JavaScript, die viele im Web zu findende
WebGL-Beispiele Web verwenden, dürfte <I>Sylvester.js<I>
sein. Ihr großer Nachteil ist, dass sie den
WebGL-Datentyp <I>Float32Array<I> nicht
unterstützt und somit viele Konvertierungen
zwischen <I>float<I> und <I>Float32Array<I> nötig
wären. Außerdem lässt <I>Sylvester.js<I> in Sachen
Performance zu wünschen übrig. Eine (nach Meinung
des Autors) bessere Lösung ist <I>glMatrix.js<I> [f].
Die schlanke Bibliothek ist speziell für WebGL
geschrieben und auf Geschwindigkeit optimiert.

Rotations- und Translationsmatrizen lassen sich
mit <I>glMatrix.js<I> komfortabel erstellen. Das
Tutorial beschränkt sich darauf, ein Quadrat in
seinem eigenen Koordinatensystem zu beschreiben
und es danach mittels Translationsmatrix und
veränderlicher Rotationsmatrix (Animation) zu
transformieren. Die Matrix zur Transformation
eines Objekts in seine Ziellage nennt man
ModelView-Matrix (<I>mvMatrix<I>, Zeile 36).
Translations- und Rotationsmatrizen lassen sich
auch ohne Zusatzbibliotheken erstellen,
<I>glMatrix.js<I> kann die Arbeit jedoch durch die
Funktionen <I>mat4.translate<I> (Zeile 38) und
<I>mat4.rotate<I> (Zeile 39), die direkt auf eine
vorhanden Matrix angewendet werden, erleichtern.

Im Listing wird zunächst eine Einheitsmatrix
angelegt und dann, wie beschrieben, so
multipliziert, dass das 3D-Objekt mit variablem
Drehwinkel vor der virtuellen Kamera positioniert
wird. Die virtuelle Kamera schaut in Richtung der
negativen z-Achse, daher steht im
Translationsvektor <I>z=-3<I> (Zeile 38). Da in                       PS: -3 statt -5 macht die Darstellung größer und erhöht die Tiefenwirkung
diesem Beispiel die 3D-Darstellung veränderlich
(animiert) ist, wird die ModelView-Matrix in der
<I>draw()<I>-Funktion erstellt (Zeile 28) und bei
jedem Aufruf von <I>draw()<I> im Vertex-Shader
aktualisiert (<I>uniformMatrix4fv<I>) (Zeile 41).

Das Beispielprogramm ruft <I>drawArrays<I> zweimal
auf (Zeile 44 und 54), um das Quadrat zweimal zu
zeichnen. Zwischen den beiden Aufrufen macht die
Anwendung nichts anderes, als die ModelView-Matrix
mit anderen Werten zu belegen und sie erneut an
den Shader zu schicken. Dieses Vorgehen lagert die
Rechenarbeit zum großen Teil auf die GPU aus.
Vertizes und Texturen liegen im Speicher nur
einmal vor.

Analog kann man die <I>drawArray<I>-Funktion noch
wesentlich häufiger mit den gleichen gebundenen
Daten und nur veränderter ModelView-Matrix
aufrufen, um eine Vielzahl gleicher Objekte in
verschiedenen Transformationen zu generieren.
Außer zum Verschieben und Drehen kann die Matrix
zur Skalierung dienen.

Nach der Transformation des Objekts in seine
Ziellage muss es projiziert werden. Die
perspektivische Projektion der 3D-Daten in die
2D-Bildschirmebene erfolgt, wie im ersten Teil des
Tutorials erläutert, ebenfalls mit Hilfe einer
Matrix (der Projektionsmatrix).

ModelView- und Projektionsmatrix befinden sich im
JavaScript-Teil des Programms. Ihre Anwendung,
also die eigentliche Berechnung, geschieht jedoch
im Vertex-Shader, einem "Mini-Programm", das auf
der GPU vielfach parallel ausgeführt werden kann.
Das Listing zeigt den Quellcode des Vertex-Shader
als im JavaScript eingebetteter String (Zeile
116).

Die OpenGL ES 2.0 Shading Language, mit der man
WebGL-Shader erstellt, erinnert in vielerlei
Hinsicht stark an C. Hauptaufgabe des
Vertex-Shader ist es, für alle zu zeichnenden
Vertizes die Transformationen zu berechnen und das
Ergebnis in der vordefinierten Variablen
<I>gl_Position<I> (Zeile 123) an den
Fragment-Shader weiterzugeben. In der
<I>main()<I>-Funktion werden die Koordinaten des
Vertex von links zuerst mit der ModelView-Matrix
und dann mit der Projektionsmatrix multipliziert
(Zeile 123). Diese Zeile veranschaulicht auch die
Bedeutung der Variablenarten <I>uniform<I> und
<I>attribute<I>, die (neben <I>varying<I>)
WebGL-Shader verwenden. Beide Matrizen sind
<I>uniform<I>, weil sie für alle Vertizes, die der
aktuelle Zeichenvorgang berechnet, gleich sind.
Die Koordinaten sind ein Attribut; sie ändern sich
bei jeder Berechnung beziehungsweise mit jedem
Vertex.

@z:3D-Texturen wirken realistischer

@$:Texturen sind (in der Regel 2D-)Grafiken, die
auf geometrisch einfachere 3D-Objekte "geklebt"
werden, um einen höheren Detailgrad zu erreichen.
Ein einfaches Beispiel könnte das 3D-Modell einer
Backsteinmauer sein, die geometrisch nur aus einem
dünnen, hohen Quader besteht. Durch eine Textur
mit Fotos von echten Mauersteinen wirkt sie trotz
der einfachen Geometrie deutlich realistischer,
wenn sie am Bildschirm als 3D-Ansicht erscheint.

WebGL kennt mehrere Arten von Texturen und Wege,
sie zu erzeugen. Ein naheliegender Fall ist, eine
JPG-Datei mit JavaScript beziehungsweise Ajax in
ein JavaScript-Image-Objekt zu laden. Alternativ
kann eine Anwendung dank HTML5 ein Image-Objekt
aus einem <I><<canvas><I>-Element extrahieren, ein
Video-Objekt als Textur verwenden oder sogar ein
<I><<canvas><I>-Element, das seinerseits
WebGL-Inhalt darstellt, als Textur für eine äußere
WebGL-Szene nutzen.

Aufgrund der Speicherverwaltung der GPU
(beziehungsweise der WebGL-Spezifikation) ist es
jedoch in allen Fällen notwendig, dass die
Texturgrafiken eine Kantenlänge von 2<+>n<+>
(1,2,4,8,...) haben. Andernfalls verweigert ein
WebGL-konformer Browser das Rendering der Szene.

Wie auch immer die Grafik erzeugt wurde, letzlich
ist sie eine Bitmap, ein 2D-Feld von RGB-Werten,
deren Ursprung (<I>0/0<I>) in der linken oberen
Ecke liegt. Da Texturgrafiken in den seltensten
Fällen das gleiche Format haben wie die
3D-Geometrie, die sie bedecken sollen, sind
Verzerrungen aller Art die Regel. Damit die Textur
so auf dem Objekt erscheint, wie es der
Programmierer beabsichtigt, benötigt er für jeden
Vertex eine Verknüpfung zu einer Texturkoordinate.
Im Beispiel besteht diese Verknüpfung aus einem
<I>Float32Array<I> (Zeile 181) mit
Texturkoordinaten in der Reihenfolge, die den
Vertexkoordinaten (Zeile 158) entspricht. Der erste Vertex im              PS: Zeilenreferenz hinzugefügt.
Array liegt links unten im Quadrat (<I>-1/-1<I>).
Ihm wird der Punkt links unten in der Grafik
(<I>0.0/1.0<I>) zugeordnet. Analog erfolgt die
Zuordnung bei den weiteren fünf Punkten der zwei
Dreiecke.

!!! Hier etwa die Abbildung

Wie zuvor für die Vertex-Koordinaten legt das
Programm für die Texturkoordinaten zunächst einen
Puffer an (Zeile 191), der als aktiver Puffer
gebunden wird (Zeile 192). Verknüpfung mit dem
Shader und Bekanntgabe des Formats
(<I>gl.FLOAT<I>, zwei Werte pro Element) erfolgen
auch hier mit <I>vertexAttribPointer<I> (Zeile
194). Sinnvollerweise und WebGL-typisch finden die
rechenintensiven Operationen in den Shadern statt.
Die Texturkoordinaten werden als <I>attribute<I>
in den Vertex-Shader übermittelt (Zeile 168 und 117) und                    PS: Zeilenreferenz hinzugefügt.        
von dort als <I>varying<I> an den Fragment-Shader
weitergegeben (Zeilen 120,124 und 129). Die Variablenart                     PS: Zeilenreferenz hinzugefügt.           
<I>varying<I> wird vom Fragment-Shader
interpoliert. Das heißt, er berechnet für alle
Pixel zwischen zwei beziehungsweise drei Vertizes
Zwischenwerte.

Der Fragment-Shader hat hier nur die Aufgabe, das
vordefinierte Objekt <I>gl_FragColor<I> (Zeile
133) zu belegen. Die ebenfalls vordefinierte
Funktion <I>texture2D<I> übernimmt die Berechnung
der Pixelfarbe anhand der Texturkoordinaten und
des Sampler, einer Sonderform der <I>uniforms<I>,
die WebGL speziell für Texturen nutzt. Da das
Beispiel nur eine einzige Textur verwendet, sind
keine weiteren Angaben erforderlich. Der Sampler
verrichtet seinen Dienst standardmäßig mit
<I>TEXTURE0<I>. WebGL kann laut Spezifikation bis
zu 32 Texturen gleichzeitig behandeln.

@z:Animation in einer Endlosschleife

@$:Wie dieser Artikel mehrfach betont hat, ist
WebGL eine Low-Level-API. Das zeigt sich auch beim
Thema Animation. Das Bewegen eines 3D-Objekts auf
dem Bildschirm heißt in diesem Fall, dass die
Anwendung die Zeichenfläche (<I>canvas<I>) mit der
Hintergrundfarbe löscht und alle sichtbaren
Objekte mit neuen Parametern (veränderte Position,
veränderter Drehwinkel,..) neu zeichnet. Im
Listing geschieht das in der Funktion
<I>WebGLObjekt.prototype.draw()<I> (Zeile 28).                              PS: Funktionsname ist korrigiert.

Das bedeutet,
dass diese Funktion für eine einfache Animation in
einer Art Endlosschleife immer wieder durchlaufen
werden muss.

Viele WebGL-Anwendungen im Web verwenden eine
einfache, aber ineffiziente Lösung, von der die
Khronos-Webseite ausdrücklich abrät. Die
JavaScript-Funktion <I>setInterval(..)<I> bietet
sich grundsätzlich für derartige Endlosschleifen
an, aber sie bringt den Browser dazu, die
Zeichenfunktion immer zu durchlaufen, also auch,
wenn zum Beispiel der Browser als Icon vorliegt
oder ein anderer Tab den Fokus hat, was unnötig
viel Rechenleistung verlangt.

Stattdessen bieten die Browser inzwischen für die
Animation die neue Funktion
<I>requestAnimationFrame()<I> an, die zweite und
letzte Hilfsfunktion, aus <I>webgl-utils.js<I>,
die das Beispielprogramm nutzt (Zeile 199). Dieser
Wrapper für <I>requestAnimationFrame<I> ist
notwendig, da die Browser sich in diesem Punkt
leider noch nicht gleich verhalten. Mit
<I>requestAnimationFrame<I> überlässt eine
Applikation dem Browser die letzte Entscheidung
darüber, ob er das nächste Bild der Animation
zeichnet oder es nicht für sinnvoll hält.

Der zeitliche Ablauf der Animation soll jedoch
unabhängig vom Zeichenverhalten des Browsers sein.
Daher nutzt die Beispielapplikation zusätzlich die
Funktion <I>animationStep<I> (Zeile 58), die die
neuen Werte der Lageparameter nach Ablauf einer
Zeiteinheit berechnet. Der Aufruf von
<I>setInterval("meinWebGLContext.animationStep()",40);<I>
(Zeile 197) kann diese Funktion in eine parallele
Endlosschleife zwingen, falls eine rein
zeitabhängige Animation gewünscht ist. Damit
"dreht" sich das Objekt weiter, auch wenn das
Browserfenster überdeckt ist, benötigt jedoch nur
noch eine minimale Rechenleistung, da es nicht
mehr gezeichnet wird.

@z:Zusammenfassung und Ausblick

@$:Dieser zweite Teil des Tutorials hat Grundlagen
zur ModelView-Matrix, Texturen und Animation
erläutert. Für die ModelView-Matrix gibt es
relativ nahe liegende Ansatzpunkt für eigene
Experimente (alle Arten von Translationen,
mehrfaches Zeichnen von Objekten,
Skalierungen,...). Das Thema Texturen und die
damit verbundenen Möglichkeiten konnte der Artikel
allerdings nur anreißen. Insbesondere Mipmapping
(verschiedene Auflösungsstufen der gleichen
Textur), Cubemap Texturen (in der Regel verwendet
als "Rundum-Hintergrund" einer 3D-Szene) sowie die
verschiedenen Optionen der Texturfilterung sind
weiterführende Stichworte [3][4].

Bei der Animation wäre der nächste Schritt, sich
von der reinen Zeitabhängigkeit zu lösen und die
Animation stattdessen über Eingaben des Anwenders
steuern zu lassen. Dazu müsste man die Maus- und
Tastaturbehandlung in JavaScript mit den
Transformationsvariablen im WebGL-Teil koppeln.

Der nächste Artikel wird das Thema Beleuchtung
und Transparenz behandeln sowie das Generieren               PS: kleine Umformulierung
und Verarbeiten größerer Dreiecksnetze. (ka)

@au1:Peter Strohm

@au2:ist als Softwareingenieur bei der BioID GmbH tätig.


@ülit:Literatur

@lit1:[1]~~Peter Strohm; Quellcode-
Matroschka; WebGL-Tutorial, Teilˇ1: Grundlagen;
<I>iX<I> 5/11, S.~~117

[2]~~Samuel R. Buss; 3D Computer Graphics: A
Mathematical Introduction with OpenGL; Cambridge
University Press 2003

@lit1:[3]~~Aaftab Munshi, Dan Ginsburg, Dave Shreiner;
OpenGL ES 2.0 Programming Guide; Addison-Wesley
Professional 2008

@lit1:[4]~~Ralph Steyer; Das JavaScript-Handbuch:
Einführung, Praxis und Referenz; Addison-Wesley
2010


!!! Anfang Kasten.1

@üfl:Eng verwandt: WebGL und OpenGL

@$:Erfahrene OpenGL-Entwickler finden in
WebGL-Projekten viele bekannte Elemente. Da beide
APIs denselben Zweck verfolgen und von der
Khronos-Gruppe veröffentlicht wurden, ist das
wenig verwunderlich. Das historisch verbindende
Element der beiden ist OpenGL ES (2.0), eine
stark verschlankte Version von OpenGL, die man an
mobile Geräte (_E_mbedded _S_ystems) anpasst hat.
Dafür hat man die für diesen Einsatzzweck
redundanten Funktionen entfernt und außerdem die
begrenzte Gleitkomma-Rechenkapazität besonders
berücksichtigt [3].

Da bei browserbasierten Anwendungen noch weniger
über die zur Verfügung stehende Hardware bekannt
ist als bei Applikationen für Smartphones et
cetera, bot es sich an, WebGL auf diesem Standard
aufzubauen, sodass eine enge Verwandtschaft
zwischen WebGL und OpenGL ES 2.0 besteht. Fast
alle API-Funktionen sind in beiden Bibliotheken
vorhanden und gleich benannt, jedoch häufig mit
leicht veränderten Parametern beziehungsweise
Datentypen zu benutzen.

!!! Ende Kasten.1


!!! Anfang Kasten.2

@üfl:Kurze WebGL-Historie

@$:Puristen vertreten oft die Ansicht, dass sich
Browser und das WWW auf die gute, schnelle und
standardkonforme Darstellung von HTML-Seiten
beschränken sollten, und stehen WebGL daher
skeptisch gegenüber. Der Trend zu Multimedia im
Web und Rich-Internet-Applications (RIAs) ist
jedoch seit Jahren ungebrochen. Audio, Video und
Vektorgrafiken sind mit HTML5 auf dem Weg dazu,
auch jenseits des Flash-Plug-in integrierter Teil
von Webseiten zu werden.

3D-Inhalte (sei es für Spiele,
Produktpräsentationen, Diagramme,
3D-Funktionsplotter et cetera) waren bisher nur
mit Behelfslösungen, Plug-ins (Google Earth,
Flash) oder Desktop-Lösungen möglich. Erst mit der
Verbreitung von WebGL-fähigen Browsern kann ein
Webseitenbetreiber "echte" 3D-Inhalte anbieten,
ohne dem Anwender erklären zu müssen, welches
Plug-in er wie installieren muss. 1995 gab es mit
VRML 1.0 (später gefolgt von Version 2.0) den
ersten Versuch, einen 3D-Standard für das Web zu
etablieren, ab 2004 folgten verschiedene weitere
Ansätze. Keiner davon ist jedoch über ein
Nischendasein hinausgekommen. Geringe Verbreitung
leistungsfähiger GPUs, zu exotische Plug-ins und
fehlende Mainstream-Anwendungen dürften die
Hauptgründe dafür sein.

Große Onlinewelten wie World of Warcraft oder
SecondLife existieren seit einigen Jahren
erfolgreich, indem sie ihre eigenen Clients
verwenden. Erst durch WebGL ist es grundsätzlich
möglich, vergleichbare Anwendungen ohne
clientseitige Installationen ("zero footprint")
direkt im Browser zu verwenden.

Die erste öffentliche Ankündigung von WebGL
erfolgte im September 2009. Apple, Mozilla, Google
und andere hatten die WebGL-Working Group
gebildet, um eine neue universelle 3D-API zu
standardisieren. Unterstützt vor allem durch
Mozillas Firefox-Entwickler konnte man kurz darauf
erste WebGL-Demos mit den Entwicklungsversionen
(Nightly-Builds, Minefield) von Firefox ansehen.

Bis zur Veröffentlichung von WebGL 1.0 dauerte es
noch circa eineinhalb Jahre, in denen in der
öffentlichen Mailingliste [b] eine intensive
Kontroverse stattfand. Parallel wurden schon,
während der Standardisierungsprozess noch lief,
WebGL-Funktionen in die Entwicklungsversionen von
Googles Chrome und Firefox eingebaut. Dadurch
konnten Mozilla und Google zeitnah zur
Veröffentlichung des Standards konforme Browser
präsentieren. Opera und Apple haben angekündigt,
in absehbarer Zeit nachzuziehen. Als einziger der
verbreiteten Browser bietet Microsofts Internet
Explorer bis auf Weiteres keine
WebGL-Unterstützung. Die nächsten Monate werden
zeigen, welche Bedeutung dies sowohl für die
Verbreitung von WebGL als auch für die des IE
haben wird.

!!! Ende Kasten.2


!!! Tutorialinhalt

Teil~~1: Initialisierung, Fehlerbehandlung,
Perspektive und erste Geometrie

<B>Teil~~2: Texturen, Animation und die ModelView-Matrix<B>

Teil~~3: Beleuchtung und einfacher 3D-Funktionsplotter

!!! BU zur Abbildung

@bu:Um die Textur korrekt auf dem Objekt zu
platzieren, muss der WebGL-Autor jeden Vertex mit
einer Texturkoordinate verknüpfen.



!!! iXtract

@x:Mit der speziell für WebGL geschriebenen
Bibliothek <I>glMatrix.js<I> lassen sich Matrizen
für 3D-Darstellungen relativ leicht erstellen.

@x:Texturen, die 3D-Objekte realistischer
erscheinen lassen, sind in WebGL Bitmaps mit
RGB-Werten.

@x:Um 3D-Anwendungen mit WebGL zu animieren,
müssen Webautoren die Zeichenfläche löschen und
die sichtbaren Objekte neu zeichnen.

!!! Kasten Onlinequellen

@ütb:Onlinequellen

@tb_web:[a]~~WebGL-Seite der Khronos Group:?<c:"web:">www.khronos.org/webgl/<$c$>

[b]~~WebGL-Mailingliste:?<c:"web:">www.khronos.org/webgl/public-mailing-list/<$c$>

[c]~~WebGL-Tutorial des Autors:?<c:"web:">www.peter-strohm.de/webgl<$c$>

[d]~~Giles Thomas WebGL-Blog:?<c:"web:">learningwebgl.com<$c$>

[e]~~webgl-utils.js: JavaScript-Bibliothek zur
Initialisierung des WebGL-Context:?<c:"web:">https://cvs.khronos.org/svn/repos/registry/trunk/public/webgl/sdk/demos/common/webgl-utils.js<$c$>

[f]~~glMatrix.js: Vektor/Matrix-JavaScript-Bibliothek für WebGL:?<c:"web:">code.google.com/p/glmatrix/<$c$>



!!! Softlinks

@softlinks_anfang:

WebGL-Seite der Khronos Group:?www.khronos.org/webgl/

WebGL-Mailingliste:?www.khronos.org/webgl/public-mailing-list/

WebGL-Tutorial des Autors:?www.peter-strohm.de/webgl

Giles Thomas WebGL-Blog:?learningwebgl.com

webgl-utils.js: JavaScript-Bibliothek zur Initialisierung des WebGL-Kontextes:?https://cvs.khronos.org/svn/repos/registry/trunk/public/webgl/sdk/demos/common/webgl-utils.js

glMatrix.js: Vektor/Matrix-JavaScript-Bibliothek für WebGL:?code.google.com/p/glmatrix/

@softlinks_ende:
