Home
WebGL Api Spickzettel
WebGL Sicherheit
Tutorial
0 : WebGL Browser
1 : Das erste Dreieck
2 : 3D-Mathematik
3 : Farbe
4 : Animation
5 : Interaktion I
6 : Texturen
7 : Beleuchtung I
8 : Interaktion II
Links
WebGL Beispiele
WebGL Frameworks
ext. WebGL Tutorials
Kontakt / Impressum
webgl ([ät)] peter-strohm Punkt de
|
3 Farbe
>>>> Direkt zum Beispiel <<<<
>>>Quellcode zum Beispiel <<<
Nachdem Kapitel 2 sehr mathematiklastig wird es jetzt wieder mehr um die Javascript-Architektur und schöne bunte Farben gehen.
Der Quellcode zum Beispiel aus Kapitel 1 hatte bewusst keine nennenswerte Strukturierung. Alle erforderlichen Schritte zur
Darstellung des Dreiecks wurden nacheinander innerhalbe einer großen Funktion abgearbeitet.
Das wird sich jetzt ändern. Obwohl funktional "nur" die Farbe hinzukommt, sieht ist der Quellcode nicht wiederzuerkennen.
Ich habe den Ablauf in einzelne in sich zusammengehörige Funktionen unterteilt und einen Hauch von Objektorientierung verwendet, soweit
Javascript dies zulässt und es mir sinnvoll erscheint.
Was die Funktionalität des Beispiels betrifft, werden das Beispiel aus Kapitel 1 so erweitern, dass jedem Eckpunkt des
Dreiecks ein eigener Farbwert zugeordnet werden kann.
Die Fläche zwischen den Eckpunkten (also die Dreiecksfläche) wird mit
interpolierten Farbwerten gefüllt.
So sieht's aus:
Bild 3.1 : Screenshot zum Beispiel 3
hier geht's zur Live-Version
(WebGL-fähiger Browser erforderlich)
Zunächst habe ich den Quellcode im Vergleich zum
ersten Beispiel etwas umstrukturiert:
Am Anfang werden zwei zusätzliche Javascript-Dateien eingebunden:
6 | <script src="webgl-utils.js" ></script>
| 7 | <script src="gl-matrix.js" ></script>
|
webgl-utils.js wird freundlicherweise von Google
zur Verfügung gestellt und hilft bei der browserunabhängigen Initialisierung
des WebGL-Contexts.
gl-matrix.js ist eine speziell
für WebGL angelegte Bibliothek von Matrix- und Vektorfunktionen. Darin findest
Du auch eine Kapselung der in Tutorial zwei beschriebenen Perspektiv- und
Projektionsmatrix, die ich verwenden werde.
In kapitel3.html
erstelle ich das globale Objekt WebGLApplication mit zunächst sechs
Properties (Eigenschaften, Elementen):
21 | WebGLApplication.Core = (function () {
| 22 | var members = {
| 23 | // Zeiger zum WebGLProgram-Objekt
| 24 | programObject: 0,
| 25 | canvas: null,
| 26 | gl: null,
| 27 | pMatrix: null,
| 28 | model: null,
| 29 | shaderVarLocations: null
| 30 | };
|
Die Kapselung der Properties wird über die folgenden setMember
und getMember Methoden realisiert. Die Technik ist
einem Heise-Artikel von Jan Petzold entnommen.
31 | return {
| 32 | getMember: function (key) {
| 33 | if (typeof members[key] !== 'undefined') {
| 34 | return members[key];
| 35 | } else {
| 36 | return false;
| 37 | }
| 38 | },
| 39 | setMember: function (key, value) {
| 40 | members[key] = value;
| 41 | }
| 42 | };
|
Der Rest des Code Refactorings ist weniger aufregend als es vielleicht beim
ersten Blick auf den Quellcode erscheinen mag.
Die Methoden
init
bufferModel
setupViewpoint
und
drawScene
werden nacheinander abgearbeitet und machen genau das, was ihr Name andeutet. :-D
Kommen wir nun endlich zur Farbe:
3.1 Der Weg der Farbe - rückwärts
Es sind mehrere Schritte zu programmieren bzw. Stufen zu durchlaufen, bevor
die Farbe auf dem Dreieck ankommt. Ich werde hier diese Schritte "rückwärts"
erläutern. D.h. wir beginnen beim letzten Schritt, dem Fragmentshader.
Wie kommen nun die Farben auf das Dreieck? :
Eine wichtige Rolle hierbei spielen wieder der Vertex- und der
Fragment-Shader. (Du erinnerst dich: Shader sind die Mini-Programme, die in
der Grafikkarte ausgeführt werden)
Sehen wir uns zunächst die Veränderung im Fragment-Shader an:
Neu : Fragmentshader mit Farbe kapitel3.html
|
Alt : alles weiß kapitel1.html
|
248 | 'precision mediump float;\n\
| 249 | varying vec4 vFarbe; \n\
| 250 | void main() \n\
| 251 | { \n\
| 252 | gl_FragColor = vFarbe;\n\
| 253 | } \n';
|
|
62 | 'precision mediump float;\n\
| 63 | void main() \n\
| 64 | { \n\
| 65 | gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n\
| 66 | } \n';
|
|
Wie du im direkten Vergleich siehst, wurde die Variable vColor
neu eingeführt. Sie ist als vec4 deklariert, hat also 4 Element: rot,
grün, blau und Opazität. Die fest definierte WebGL-Variable
gl_FragColor wird mit dem Wert von vColor belegt.
Mit anderen Worten: vColor wird "durchgereicht".
Wie kommt nun der Farbwert in vColor ? Zur Beantwortung dieser
Frage müssen wir uns zunächst mit dem Schlüsselwort
varying auseinandersetzen.
Variablen die mit dem Schlüsselwort varying gekennzeichnet sind bilden
eine Schnittstelle zwischen Vertex- und Fragment-Shader. Sie sind im Vertexshader
AUSGANGSvariablen und im Fragmentshader EINGANGSvariablen. Demzufolge müssen
sie in beiden Shadern vom gleichen Typ sein und den gleichen Namen tragen wie
du hier im neuen Vertex-Shader sehen kannst:
236 | 'attribute vec4 av4Position; \n\
| 237 | attribute vec4 av4VertexFarbe; \n\
| 238 | uniform mat4 um4PerspektivMatrix; \n\
| 239 | uniform mat4 um4ModelviewMatrix; \n\
| 240 | varying vec4 vFarbe; \n\
| 241 | void main() \n\
| 242 | { \n\
| 243 | gl_Position = um4PerspektivMatrix * um4ModelviewMatrix * av4Position; \n\
| 244 | vFarbe = av4VertexFarbe; \n\
| 245 | } \n';
|
Wie du siehst passiert auch im Vertex-shader mit der Farbe nichts
aufregendes: Sie wird als attribute vec4 av4VertexFarbe
in den Vertexshader hineingegeben und
als vFarbe wie gerade
beschrieben an den Fragmentshader weitergegeben. Kurz gesagt: die
Farbe wird unverändert durchgereicht.
Dir fällt sicherlich auf, dass Zeile 1 und 2 des Vertexshaders sehr ähnlich
aussehen. Position und Farbe der einzelnen Vertices werden hier praktisch
gleich behandelt: Beides sind Vektoren die "von
außen" mit Inhalt gefüllt werden.
Hier als kleiner Einschub die drei Schlüsselwörter vor Variablen in den
Shader-scripten in der Übersicht:
attribute
|
Attribute (attribute ) sind Variablen, die sich speziell
auf Vertices beziehen und nur im Vertex-Shader verwendet werden.
Typisches Beispiel sind die Koordinaten (x,y,z). Ihr Wert unterscheidet
sich i.d.R. von einem Vertex zum nächsten.
|
uniform
|
Als uniform werden Shadervariablen gekennzeichnet, die außerhalb der
Shader "einheitlich" (uniform) festgelegt werden. Sie können sowohl in
Vertex- als auch in Fragmentshader verwendet werden. Ein Beispiele sind
die Modelview oder Perspektivmatrix. Beide werden außerhalb der Shader
berechnet und in den Shadern nicht mehr verändert.
|
varying
|
"varying" Variablen bilden die Schnittstelle zwischen Vertex- und
Fragmentshader. Ihr Inhalt wird vom Vertex-Shader an den Fragmentshader
weitergegeben. Varyings müssen in beiden Shadern mit jeweils gleichem
Namen und Typ deklariert werden.
Varying werden bei der Rasterung automatisch zwischen den Vertices
interpoliert. Im Beispiel zu diesem Kapitel sieht man diese
Interpolation sehr gut am Farbverlauf des Dreiecks: die drei Vertices
haben festgelegte Farben, die Fläche dazwischen wird vom Fragmentshader
mit interpolierten "Zwischenfarben" gefüllt.
|
Tabelle 3.1 : die drei Shader-Spezialvariablentypen
Die Schlüsselwörter in Tabelle 3.1 werden auch bei anderen Themen wieder
auftauchen.
Verfolgen wir den Weg der Farbe weiter. Zuletzt hast du gesehen, dass der
Farbwert durch den Vertex-Shader durchgereicht wird. Wie kommt der Wert nun in
den Vertex-Shader hinein?
Die Antwort liegt in Zeile 68 von kapitel3.html.
Dort wird mit der update() -Methode von
ShaderVarLocations ermittelt, welche "Adressen" die Attribute und
Uniforms im Vertex-Shader haben.
Mit diesen Adressen wird WebGL in der drawScene() Methode in den
Zeilen 211 - 213 (für die Farbe) mitgeteilt, zu welcher Buffer zu welchem
Attribut gehört und in welchem Datenformat der Buffer zu lesen ist (4
Element bilden eine Farbe, alle Elemente sind vom Typ gl.FLOAT).
211 | gl.bindBuffer(gl.ARRAY_BUFFER, Model.colorBuffer);
| 212 | gl.vertexAttribPointer(shaderVarLocations.colorAttribute, 4, gl.FLOAT, false, 0, 0);
| 213 | gl.enableVertexAttribArray(shaderVarLocations.colorAttribute);
|
Das zugehörige Float32Array mit den drei
vierdimensionalen Farbwerten wurde bereits in den Zeilen 185 bis 192 erzeugt und als
Buffer an die Shader übergeben.
185 | Model.colors = new Float32Array([
| 186 | 1.0, 0.0, 0.0, 1.0, //rot
| 187 |
| 188 | 0.0, 0.0, 1.0, 1.0]); //blau
| 189 |
| 190 | Model.colorBuffer = gl.createBuffer();
| 191 | gl.bindBuffer(gl.ARRAY_BUFFER, Model.colorBuffer);
| 192 | gl.bufferData(gl.ARRAY_BUFFER, Model.colors, gl.STATIC_DRAW);
|
Wenn dir die RGBAlpha Farbdarstellung
geläufig ist, kannst du hier die Farben der einzelnen Dreieckspunkte verändern.
Die Farbwerte zwischen den Vertices wird der Fragmentshader automatisch
für jeden Pixel interpolieren.
createBuffer() erzeugt einen neuen Puffer im Grafikspeicher. Die
Daten werden mit bindBuffer und bufferData an WebGL
bzw. die GPU übergeben.
Ich habe den Signalfluss der Farbe in dieseem Kapitel "von innen nach außen"
beschrieben. Wenn Du das soweit nachvollzogen hast, kannst du dir die
parallele Kette der VertexPOSITIONEN im Quellcode anschauen. Das Prinzip ist
sehr ähnlich.
Im nächsten Kapitel werde ich mich dem Thema Animation zuwenden. Es bleibt
spannend!
Thanks to Giles Thomas and his project
LearningWebGL.com
|