WebGL - Zeichnungsmodi

Hallo, zukünftige WebGL-Zauberer! ? Heute tauchen wir in die aufregende Welt der Zeichnungsmodi in WebGL ein. Als dein freundlicher Nachbar-Computerlehrer bin ich hier, um dich durch diese Reise zu führen, selbst wenn du noch nie eine Zeile Code geschrieben hast. Also, hole dir deine virtuelle Pinsel und lasst uns einige digitale Meisterwerke schaffen!

WebGL - Modes of Drawing

Der Modus-Parameter

Bevor wir mit dem Zeichnen beginnen, lassen wir uns über den Stern unseres Programms unterhalten: den mode-Parameter. Stell dir vor, es ist der magische Zauberstab, der WebGL sagt, wie er die Punkte (oder in unserem Fall, Vertexen) verbinden soll, um verschiedene Formen und Muster zu erstellen.

In WebGL, wenn wir die Funktion gl.drawArrays() oder gl.drawElements() aufrufen, müssen wir einen mode-Parameter angeben. Dieser Parameter ist wie das Geben von Anweisungen für ein Verbinde-die-Punkte-Puzzle – er sagt WebGL, wie er die von uns definierten Punkte verbinden soll.

Hier ist eine Tabelle der verschiedenen Zeichnungsmodi, die in WebGL verfügbar sind:

Modus Beschreibung
gl.POINTS Zeichnet einen einzelnen Punkt für jeden Vertex
gl.LINES Zeichnet eine Linie zwischen jedem Paar von Vertexen
gl.LINE_STRIP Zeichnet eine fortlaufende Linie, die die Vertexen verbindet
gl.LINE_LOOP Ähnlich wie LINE_STRIP, aber schließt die Form ab
gl.TRIANGLES Zeichnet ein Dreieck für jedes trio von Vertexen
gl.TRIANGLE_STRIP Zeichnet eine verbundenen Gruppe von Dreiecken
gl.TRIANGLE_FAN Zeichnet eine fächerartige Form aus verbundenen Dreiecken

Mach dir keine Sorgen, wenn diese jetzt verwirrend erscheinen. Wir werden jeden von ihnen mit Beispielen durchgehen!

Beispiel – Zeichne drei parallele Linien

Lassen wir mit einem einfachen Beispiel beginnen: das Zeichnen von drei parallelen Linien. Dies wird uns helfen zu verstehen, wie der mode-Parameter in der Praxis funktioniert.

// Zuerst einrichten wir unseren WebGL-Kontext
const canvas = document.getElementById('myCanvas');
const gl = canvas.getContext('webgl');

// Nun definieren wir unseren Vertex-Shader
const vertexShaderSource = `
attribute vec2 a_position;
void main() {
gl_Position = vec4(a_position, 0.0, 1.0);
}
`;

// Und unseren Fragment-Shader
const fragmentShaderSource = `
precision mediump float;
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // Rote Farbe
}
`;

// Shaders erstellen und kompilieren (macht euch keine Sorgen, wir erklären das ausführlich in zukünftigen Lektionen)
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);

const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);

// Ein Programm erstellen und die Shaders verknüpfen
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);

// Die Positionen unserer Linien definieren
const positions = new Float32Array([
-0.8, -0.8,  // Linie 1 Start
-0.8,  0.8,  // Linie 1 Ende
-0.3, -0.8,  // Linie 2 Start
-0.3,  0.8,  // Linie 2 Ende
0.2, -0.8,  // Linie 3 Start
0.2,  0.8   // Linie 3 Ende
]);

// Ein Buffer erstellen und die Positionen hineinlegen
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);

// WebGL mitteilen, wie der Buffer gelesen werden soll und dem `a_position`-Attribut zugeordnet wird
const positionAttributeLocation = gl.getAttribLocation(program, 'a_position');
gl.enableVertexAttribArray(positionAttributeLocation);
gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);

// Die Leinwand leeren
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);

// Die Linien zeichnen
gl.drawArrays(gl.LINES, 0, 6);

Lassen wir das einmal auseinandernehmen:

  1. Wir richten unseren WebGL-Kontext ein und definieren unsere Shaders. Macht euch keine Sorgen um diese jetzt; wir werden Shaders in Zukunft ausführlich behandeln.

  2. Wir erstellen ein Programm und verknüpfen unsere Shaders. Das ist wie das Vorbereiten unseres digitalen Pinsels.

  3. Wir definieren die Positionen unserer Linien. Jede Linie wird durch zwei Punkte definiert (ihren Anfang und ihr Ende), und jeder Punkt wird durch zwei Koordinaten (x und y) definiert. Also haben wir insgesamt 6 Punkte für unsere 3 Linien.

  4. Wir erstellen ein Buffer und legen unsere Positionen hinein. Das ist wie das Laden unserer Farbe auf den Pinsel.

  5. Wir sagen WebGL, wie er diesen Buffer lesen soll und ordnen ihn dem a_position-Attribut in unserem Vertex-Shader zu.

  6. Schließlich rufen wir gl.drawArrays(gl.LINES, 0, 6) auf. Hier passiert die Magie!

Führt diesen Code aus, und voilà! Ihr solltet drei rote parallele Linien auf einem schwarzen Hintergrund sehen. Gratulation, ihr habt gerade eure erste WebGL-Zeichnung geschaffen! ?

Zeichnungsmodi

Nun, da wir gl.LINES in Aktion gesehen haben, lassen uns einige andere Zeichnungsmodi erkunden. Wir verwenden die gleiche Einrichtung wie zuvor, ändern aber die Positionen und den Zeichnungsmodus.

gl.POINTS

Beginnen wir mit dem einfachsten Modus: gl.POINTS. Dieser Modus zeichnet einen einzelnen Punkt für jeden Vertex.

// ... (vorherige Einrichtungscodes)

const positions = new Float32Array([
-0.5, 0.5,
0.0, 0.0,
0.5, -0.5
]);

// ... (Buffer-Einrichtungscodes)

gl.drawArrays(gl.POINTS, 0, 3);

Dies wird drei rote Punkte auf eurer Leinwand zeichnen. Einfach, nicht wahr?

gl.LINE_STRIP

Jetzt probieren wir gl.LINE_STRIP. Dieser Modus zeichnet eine fortlaufende Linie, die die Vertexen verbindet.

// ... (vorherige Einrichtungscodes)

const positions = new Float32Array([
-0.5, 0.5,
0.0, -0.5,
0.5, 0.5
]);

// ... (Buffer-Einrichtungscodes)

gl.drawArrays(gl.LINE_STRIP, 0, 3);

Ihr solltet eine V-förmige Linie sehen, die die drei Punkte verbindet.

gl.LINE_LOOP

gl.LINE_LOOP ist ähnlich wie LINE_STRIP, aber er schließt die Form ab, indem er den letzten Vertex mit dem ersten verbindet.

// ... (vorherige Einrichtungscodes)

const positions = new Float32Array([
-0.5, 0.5,
0.0, -0.5,
0.5, 0.5
]);

// ... (Buffer-Einrichtungscodes)

gl.drawArrays(gl.LINE_LOOP, 0, 3);

Dies wird eine Dreieckscontour zeichnen.

gl.TRIANGLES

Nun zu gl.TRIANGLES. Dieser Modus zeichnet ein separates Dreieck für jedes trio von Vertexen.

// ... (vorherige Einrichtungscodes)

const positions = new Float32Array([
-0.5, -0.5,
0.5, -0.5,
0.0, 0.5
]);

// ... (Buffer-Einrichtungscodes)

gl.drawArrays(gl.TRIANGLES, 0, 3);

Ihr solltet ein rotes Dreieck sehen.

gl.TRIANGLE_STRIP

gl.TRIANGLE_STRIP ist etwas komplexer. Er zeichnet eine gruppierte Gruppe von Dreiecken, wobei jedes Dreieck zwei Vertexen mit dem vorherigen teilt.

// ... (vorherige Einrichtungscodes)

const positions = new Float32Array([
-0.5, -0.5,
0.5, -0.5,
-0.5, 0.5,
0.5, 0.5
]);

// ... (Buffer-Einrichtungscodes)

gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

Dies wird zwei verbundene Dreiecke zeichnen, die ein Rechteck bilden.

gl.TRIANGLE_FAN

Schließlich schauen wir uns gl.TRIANGLE_FAN an. Dieser Modus zeichnet eine fächerartige Form, bei der alle Dreiecke den ersten Vertex als gemeinsamen Punkt haben.

// ... (vorherige Einrichtungscodes)

const positions = new Float32Array([
0.0, 0.0,    // Mittelpunkt
0.5, 0.0,    // Punkt 1
0.35, 0.35,  // Punkt 2
0.0, 0.5,    // Punkt 3
-0.35, 0.35  // Punkt 4
]);

// ... (Buffer-Einrichtungscodes)

gl.drawArrays(gl.TRIANGLE_FAN, 0, 5);

Dies wird eine Form zeichnen, die ein bisschen wie ein Viertelkreis aussieht.

Und das war's! Wir haben alle Zeichnungsmodi in WebGL erkundet. Denken daran, der Schlüssel zum Beherrschen dieser ist die Übung. Versucht verschiedene Modi zu kombinieren, Farben zu ändern und Vertex-Positionen zu spielen. Bald werdet ihr komplexe WebGL-Szenen mit Leichtigkeit erstellen können!

In unserer nächsten Lektion tauchen wir tiefer in Shaders ein und lernen, wie man unseren Zeichnungen mit Farben und Texturen das gewisse Etwas verleiht. Bis dahin, viel Spaß beim Coden, zukünftige WebGL-Künstler! ??‍??‍?

Credits: Image by storyset