Übungen: OpenGL & Shader

Übungen zu Kapitel 4: OpenGL und Kapitel 6: Shaderprogrammierung. Geübt wird der komplette Datenpfad von der CPU zur GPU: interleaved Array, VBO (Vertex Buffer Object), VAO (Vertex Array Object) mit stride/offset in Bytes, IBO (Index Buffer Object) und die Zeichenbefehle, dazu die GLSL-Shaderprogrammierung (Vertex/Fragment, die Qualifizierer in/out/uniform, layout(location), gl_Position und Swizzling). Rechne alle Zahlenaufgaben selbst durch, bevor du die Lösung aufklappst. Merkregel für fast alles: ein float = 4 Byte.


Beginner

Aufgabe 1 (Beginner) - State-Machine und Explizitheit

OpenGL wird als "State-Machine" (state machine) und als "explizit" (explicit) beschrieben. Erkläre beide Eigenschaften in je einem Satz und nenne je ein Beispiel.

Lösung anzeigen

State-Machine (Zustandsautomat): OpenGL merkt sich einen internen Zustand. Funktionen ändern diesen Zustand oder nutzen ihn zur Darstellung. Einmal gesetzt, bleibt ein Zustand aktiv, bis er umgeschaltet wird.

  • Beispiel: das aktuell gebundene VBO/VAO oder die aktuelle Farbe. Im Legacy-glBegin/glEnd-Block gilt eine mit glColor4f gesetzte Farbe fuer alle folgenden Vertices, bis sie neu gesetzt wird.

Explizitheit: Was nicht explizit aktiviert wurde, bleibt aus.

  • Beispiel: Eine Transparenz (Alpha) zu setzen bringt nichts, solange die Transparenzberechnung (Blending) nicht explizit eingeschaltet ist. Ebenso müssen Vertex-Attribute mit glEnableVertexAttribArray erst aktiviert werden.

Tipp: Beide Begriffe sind laut Prüfungsrelevanz ein klassischer Erklär-Klassiker. Merke dir je ein Beispiel dazu.

Siehe Kapitel 4: OpenGL.


Aufgabe 2 (Beginner) - Der 3-Schritte-VBO-Upload

Ein VBO wird in genau drei Schritten mit Daten befüllt. Nenne die drei Schritte in der richtigen Reihenfolge mit dem jeweiligen OpenGL-Befehl.

Lösung anzeigen
  1. ID erzeugen - glGenBuffers
  2. Buffer aktivsetzen (binden) - glBindBuffer(GL_ARRAY_BUFFER, vboID)
  3. Daten hochladen - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices, GL_STATIC_DRAW)

Der usage hint im dritten Schritt beschreibt die Nutzung:

  • GL_STATIC_DRAW - einmal initialisiert, oft gerendert.
  • GL_DYNAMIC_DRAW - oft geändert.
  • GL_STREAM_DRAW - selten genutzt.

Typischer Fehler: GL_ARRAY_BUFFER (Geometriedaten) mit GL_ELEMENT_ARRAY_BUFFER (Indizes im IBO) verwechseln.

Siehe Kapitel 4: OpenGL.


Aufgabe 3 (Beginner) - Vertex-Shader vs. Fragment-Shader

Ordne zu: Welche Stufe berechnet die finale Position und welche die Farbe jedes Pixels? Welche eingebaute Variable muss jede Stufe befuellen?

Lösung anzeigen
StufeAufgabeläuft proPflicht-Ausgabe
Vertex Shaderfinale Position jedes VertexVertexgl_Position (homogen, vec4)
Fragment ShaderFarbe jedes Pixels/FragmentsFragmentmind. eine Output-Variable (z.B. out vec4 color;)

Die zwei Pflichten:

  1. Jeder Vertex-Shader MUSS gl_Position setzen.
  2. Jeder Fragment-Shader MUSS mind. eine Output-Variable definieren und mit der finalen Farbe füllen.

Typischer Fehler: "pro Fragment/Pixel" und "pro Vertex" verwechseln. Merke: Vertex = Eckpunkt (Position), Fragment = Pixel-Kandidat (Farbe).

Siehe Kapitel 6: Shaderprogrammierung.


Aufgabe 4 (Beginner) - Wozu dient das VAO?

Es heisst "OpenGL ist dumm". Was bedeutet das im Zusammenhang mit VBO und VAO? Welche Aufgabe hat das VAO?

Lösung anzeigen

OpenGL sieht im VBO nur ein Bündel rohen Speicher (rohe Bytes) und "versteht" die Struktur nicht. Das VAO (Vertex Array Object) beschreibt, wie die rohen VBO-Daten zu interpretieren sind:

  • Es speichert Attributzeiger (vertex attribute pointers), je einen pro Vertex-Attribut, mit einem Attribut-Index (z.B. Attribut 0 = Position, Attribut 1 = Farbe).
  • Es wird über glVertexAttribPointer(index, size, type, normalized, stride, offset) gefüllt.
  • Nur ein VAO kann gleichzeitig aktiv sein.

Typischer Fehler: Glauben, OpenGL "versteht" die Datenstruktur von selbst. Nein: erst das VAO liefert die Interpretation.

Siehe Kapitel 4: OpenGL.


Fortgeschritten

Aufgabe 5 (Fortgeschritten) - stride und offset berechnen (interleaved)

Gegeben ist ein interleaved Array mit pro Vertex: Position (3 floats) + Farbe (3 floats). Berechne für ein glVertexAttribPointer-Setup:

  1. den stride,
  2. den offset der Position,
  3. den offset der Farbe.
Lösung anzeigen

Ein float = 4 Byte; pro Vertex liegen 3+3=63 + 3 = 6 floats.

stride=6×4=24 Byte\text{stride} = 6 \times 4 = 24\ \text{Byte} offsetPos=0,offsetFarbe=3×4=12 Byte\text{offset}_{\text{Pos}} = 0, \qquad \text{offset}_{\text{Farbe}} = 3 \times 4 = 12\ \text{Byte}

Als Code:

glVertexAttribPointer(0, 3, GL_FLOAT, false, 24, 0);          // Position, ID 0
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, false, 24, (void*)12);  // Farbe, ID 1
glEnableVertexAttribArray(1);

Der offset 12 wird als (void*)12 gecastet (der "seltsame Datentyp").

Typischer Fehler: stride/offset in Elementen statt in Bytes angeben. Beide sind in Bytes: 3 Positions-floats ergeben offset 12, nicht 3. Und: Attribute mit glEnableVertexAttribArray aktivieren, sonst ist nichts sichtbar.

Siehe Kapitel 4: OpenGL.


Aufgabe 6 (Fortgeschritten) - count bei glDrawElements

Ein Objekt besteht aus 5 Dreiecken, gezeichnet mit glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, 0). Wie gross ist count? Begründe.

Lösung anzeigen

count ist die Anzahl der Indizes, nicht die Anzahl der Dreiecke. Bei GL_TRIANGLES hat jedes Dreieck 3 Indizes:

count=3×nDreiecke=3×5=15count = 3 \times n_{\text{Dreiecke}} = 3 \times 5 = 15

Das Index-Array besteht aus Dreier-Gruppen, z.B. V0 V1 V2 | V2 V1 V3 | V2 V3 V4 | .... Beim Aufruf müssen zusätzlich der Primitivtyp (GL_TRIANGLES) und der IBO-Datentyp (GL_UNSIGNED_INT; alternativ GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT) angegeben werden.

Typischer Fehler: count als Anzahl Dreiecke annehmen (hier fälschlich 5). Richtig ist 3×5=153 \times 5 = 15.

Siehe Kapitel 4: OpenGL.


Aufgabe 7 (Fortgeschritten) - in / out / uniform und ihre Rechte

Vervollständige die Tabelle: Rolle und Zugriffsrecht (READ-ONLY oder READ/WRITE) für die drei Qualifizierer. Was bedeutet "interpoliert" bei out?

Lösung anzeigen
QualifiziererRolleRechte
inEingabe aus vorheriger Stufe; pro Vertex bzw. pro FragmentREAD-ONLY
outWeitergabe an die nächste Stufe (Vertex -> Fragment), interpoliertREAD/WRITE
uniformEingabe von OpenGL/Anwendung in ein Shader-Programm; konstant während des RendervorgangsREAD-ONLY

Interpoliert: Die out-Werte des Vertex-Shaders werden auf dem Weg zum Fragment-Shader automatisch zwischen den Vertexdaten interpoliert (perspektivkorrekt über das Primitiv). So entsteht z.B. aus drei Eckfarben ein weicher Farbverlauf über die Fläche.

Kopplung out/in: funktioniert nur bei gleichem Variablennamen UND gleichem Typ in beiden Shadern.

Typischer Fehler: uniform als beschreibbar oder als pro-Vertex-variabel annehmen. Es ist READ-ONLY und pro Draw-Call konstant. Und: Uniforms werden per Name adressiert (glGetUniformLocation), nicht per Index.

Siehe Kapitel 6: Shaderprogrammierung.


Aufgabe 8 (Fortgeschritten) - Vertex-Shader vervollständigen

Ergänze die fehlenden Zeilen (Lücken mit /* ? */), sodass ein minimaler Vertex-Shader entsteht, der ein Attribut aus VAO-Index 0 einliest und die homogene Position setzt:

#version 330
layout(location = 0) in vec3 vertex;

uniform mat4 model;

void main()
{
    gl_Position = /* ? */;
}
Lösung anzeigen
#version 330
layout(location = 0) in vec3 vertex;

uniform mat4 model;

void main()
{
    gl_Position = model * vec4(vertex, 1.0);
}

Begründung:

  • vec4(vertex, 1.0) homogenisiert die 3D-Position: w=1.0w = 1.0 bedeutet ein Punkt (keine Richtung).
  • Die Multiplikation mit der akkumulierten Transformationsmatrix model liefert die finale Position:
gl_Position=model(vertex,1.0)\texttt{gl\_Position} = \mathbf{model} \cdot (\texttt{vertex}, 1.0)
  • layout(location = 0) bindet die in-Variable an das VAO-Attribut mit Index 0 (aus glVertexAttribPointer(0, ...)).

Typischer Fehler: Homogenisierung vergessen und versehentlich w=0w = 0 schreiben (das wäre eine Richtung, kein Punkt). Und: GLSL prüft layout(location = ...) nicht gegen die tatsächlichen VBO-Daten - der Programmierer muss selbst wissen, was das Attribut enthält.

Siehe Kapitel 6: Shaderprogrammierung.


Anspruchsvoll

Aufgabe 9 (Anspruchsvoll) - Swizzling: L-Value-Auswertung

Gegeben:

vec4 v = vec4(1.0, 2.0, 3.0, 4.0);
v.zx = vec2(7.0, 8.0);
v.yw = vec2(9.0, 5.0);
  1. Was ist der Wert von v nach diesen beiden gültigen Zuweisungen?
  2. Warum sind v.xx = vec2(1.0, 2.0); und v.yz = 3.0; jeweils Fehler?
Lösung anzeigen

Schritt für Schritt (Start: v = (1, 2, 3, 4)):

  • v.zx = vec2(7.0, 8.0) weist der Reihenfolge nach zu: z = 7, x = 8. Also v = (8, 2, 7, 4).
  • v.yw = vec2(9.0, 5.0) weist zu: y = 9, w = 5. Also v = (8, 9, 7, 5).

Ergebnis: v = (8.0, 9.0, 7.0, 5.0).

Die Fehler:

  • v.xx = vec2(1.0, 2.0) ist ungültig, weil beim schreibenden Zugriff (L-Value) jede Komponente nur einmal genannt werden darf. x doppelt zu nennen ist verboten (Smearing ist nur beim Lesen erlaubt).
  • v.yz = 3.0 ist ein Type mismatch: links steht ein Swizzle mit zwei Komponenten (vec2), rechts ein Skalar. Korrekt wäre z.B. v.yz = vec2(3.0), was durch Smearing (3.0, 3.0) erzeugt.

Tipp: Beim Lesen (R-Value) sind Wiederholungen erlaubt (v.xxx, v.yyxx); beim Schreiben (L-Value) nicht. Die drei Sets .xyzw / .rgba / .stqp dürfen innerhalb eines Zugriffs nie gemischt werden (v.xgp ist Fehler).

Siehe Kapitel 6: Shaderprogrammierung.


Aufgabe 10 (Anspruchsvoll) - Vertices und Indizes zählen

Betrachte ein Gitter (fan/strip-artige Anordnung) aus 6 Dreiecken, die sich gemeinsame Eckpunkte teilen.

  1. Wie viele Vertices müsstest du bei glDrawArrays mit GL_TRIANGLES (ohne Wiederverwendung, sequenziell) hochladen und zeichnen?
  2. Wie viele Indizes braucht dagegen glDrawElements mit GL_TRIANGLES (IBO)?
  3. Was ist der Vorteil des IBO-Ansatzes?
Lösung anzeigen

1. glDrawArrays (brute-force, sequenziell): jeder Vertex jedes Dreiecks wird einzeln abgelegt, ohne Wiederverwendung:

3×nDreiecke=3×6=18 Vertices3 \times n_{\text{Dreiecke}} = 3 \times 6 = 18\ \text{Vertices}

Gezeichnet wird mit glDrawArrays(GL_TRIANGLES, first, count) und count=18count = 18 (Primitive von firstfirst bis first+count1first + count - 1).

2. glDrawElements (indiziert): die Anzahl der Indizes ist ebenfalls

count=3×nDreiecke=3×6=18 Indizescount = 3 \times n_{\text{Dreiecke}} = 3 \times 6 = 18\ \text{Indizes}

Der Unterschied liegt nicht in der Index-Anzahl, sondern darin, dass im VBO gemeinsam genutzte Vertices nur einmal gespeichert werden. Der IBO verweist mehrfach auf denselben Vertex (z.B. V0 V1 V2 | V2 V1 V3 | ...).

3. Vorteil: Wiederverwendung von Vertices -> weniger Datentransfer (der VBO-Speicher schrumpft, da geteilte Ecken nicht dupliziert werden), höhere Flexibilität (Teilrendering durch Anpassung des IBO möglich).

Typischer Fehler: count bei glDrawElements mit der Anzahl Dreiecke gleichsetzen. count ist immer die Anzahl der Indizes (=3×= 3 \times Dreiecke bei GL_TRIANGLES). Der Spareffekt des IBO steckt im VBO (weniger Vertexdaten), nicht in einem kleineren count.

Siehe Kapitel 4: OpenGL.


Aufgabe 11 (Anspruchsvoll) - Triangle Strip: Vertices vs. Dreiecke

Hinweis: Die eigentliche Primitiv-Art GL_TRIANGLE_STRIP gehört zum Themenblock "Primitive" (Kapitel 3). In Kapitel 4: OpenGL taucht das strip-typische Wiederverwendungs-Muster als Index-Reihenfolge auf (V0 V1 V2 | V2 V1 V3 | V2 V3 V4 | ...). Die folgende Zählformel ist die Standardregel für Triangle Strips; die konkreten glDraw*-Byte- und count-Regeln stammen aus Kapitel 4.

Ein Triangle Strip (Dreiecksstreifen) besteht aus einer fortlaufenden Vertex-Folge, bei der jedes neue Dreieck die letzten zwei Vertices des vorherigen weiterverwendet.

  1. Wie viele Dreiecke entstehen aus einem Strip mit 8 Vertices?
  2. Wie viele Vertices bräuchte man für 10 Dreiecke als Strip?
  3. Wie viele Vertices bräuchte glDrawArrays mit GL_TRIANGLES (ohne Strip, ohne Wiederverwendung) für dieselben 10 Dreiecke, und wie gross ist die Ersparnis?
Lösung anzeigen

Beim Triangle Strip gilt: mit VV Vertices entstehen V2V - 2 Dreiecke (die ersten 3 Vertices bilden das erste Dreieck, jeder weitere Vertex fügt genau ein Dreieck hinzu). Umgekehrt: nn Dreiecke brauchen n+2n + 2 Vertices.

1. 88 Vertices 82=6\rightarrow 8 - 2 = \mathbf{6} Dreiecke.

2. 1010 Dreiecke 10+2=12\rightarrow 10 + 2 = \mathbf{12} Vertices.

3. glDrawArrays mit GL_TRIANGLES bräuchte 3×10=303 \times 10 = \mathbf{30} Vertices. Ersparnis des Strips:

3012=18 Vertices weniger30 - 12 = 18\ \text{Vertices weniger}

Das ist genau das Prinzip "Wiederverwendung von Vertices = weniger Datentransfer", das auch der IBO verfolgt.

Tipp: Verwechsle die beiden Formeln nicht. Strip: Dreiecke =V2= V - 2. Reines GL_TRIANGLES: Vertices/Indizes =3×= 3 \times Dreiecke.

Siehe Kapitel 4: OpenGL.


Aufgabe 12 (Anspruchsvoll) - Datenweitergabe Vertex -> Fragment

Der folgende Shader-Ausschnitt soll ein Farb-Attribut von der Vertex- zur Fragment-Stufe durchreichen, damit ein interpolierter Farbverlauf entsteht. Fülle die drei Lücken und erkläre, warum der Fragment-Output color und das Vertex-Attribut color sich nicht in die Quere kommen.

// Vertex Shader
#version 330
layout(location = 0) in vec3 vertex;
layout(location = 1) in vec3 color;

/* Lücke A: Ausgabe deklarieren */

uniform mat4 model;

void main()
{
    gl_Position = model * vec4(vertex, 1.0);
    /* Lücke B: Farbe weitergeben */
}
// Fragment Shader
#version 330
out vec4 color;

/* Lücke C: Eingabe deklarieren */

void main()
{
    color = passOn;
}
Lösung anzeigen
// Vertex Shader
out vec4 passOn;                 // Lücke A
// ...
passOn = vec4(color, 1.0);       // Lücke B (color ist hier das vec3-Attribut aus location 1)
// Fragment Shader
in vec4 passOn;                  // Lücke C

Warum kein Konflikt? Die Kopplung zwischen den Shadern läuft ausschliesslich über passOn (gleicher Name, gleicher Typ vec4 in beiden Shadern). Der Fragment-Output color (out vec4) und das Vertex-Attribut color (in vec3, location 1) sind verschiedene Variablen in verschiedenen Shadern, die nur zufällig denselben Namen tragen. Sie sind nicht miteinander verbunden.

Da out-Werte automatisch interpoliert werden, ergibt sich statt einer einfarbigen Fläche ein Farbverlauf über das Primitiv.

Typischer Fehler: out/in mit unterschiedlichem Namen oder Typ deklarieren, sodass keine Verbindung entsteht. Bedingung ist immer: gleicher Name UND gleicher Typ.

Siehe Kapitel 6: Shaderprogrammierung.


Klausur-Niveau

Aufgabe 13 (Klausur-Niveau) - Fill-the-gap: minimaler Shader + die zwei Pflichten

Vervollständige das durchgehende Klausurbeispiel (rotes Quadrat). Fülle alle mit ______ markierten Lücken und benenne anschliessend die "zwei Pflichten" von Vertex- und Fragment-Shader.

// Vertex Shader
#version 330
layout(location = ______) in vec3 vertex;   // (1)

uniform ______ model;                        // (2)

void main()
{
    ______ = model * vec4(vertex, ______);   // (3) und (4)
}
// Fragment Shader
#version 330
______ vec4 color;                           // (5)

void main()
{
    color = vec4(1.0, 0.0, 0.0, ______);     // (6)
}
Lösung anzeigen

Lösungen der Lücken:

#LückeLösungGrund
(1)layout(location = __)0verweist auf VAO-Attribut mit Index 0 (aus glVertexAttribPointer(0, ...))
(2)uniform __ modelmat4die Transformationsmatrix ist eine 4x4-Matrix
(3)__ = model * ...gl_Positioneingebaute Pflicht-Ausgabe des Vertex-Shaders
(4)vec4(vertex, __)1.0Homogenisierung: w=1.0w = 1.0 (Punkt, keine Richtung)
(5)__ vec4 coloroutFragment-Shader braucht mind. eine Output-Variable
(6)vec4(1.0, 0.0, 0.0, __)1.0Alpha = 1.0 (voll deckend) -> reines Rot

Vollständig:

// Vertex Shader
#version 330
layout(location = 0) in vec3 vertex;
uniform mat4 model;
void main() { gl_Position = model * vec4(vertex, 1.0); }
// Fragment Shader
#version 330
out vec4 color;
void main() { color = vec4(1.0, 0.0, 0.0, 1.0); }

Die zwei Pflichten:

  1. Jeder Vertex-Shader MUSS gl_Position mit der homogenen Vertexposition (vec4) füllen. Hier: model * vec4(vertex, 1.0).
  2. Jeder Fragment-Shader MUSS mind. eine Output-Variable definieren (out vec4 color;) und mit der finalen Farbe füllen.

Tipp: #version 330 steht für OpenGL/GLSL 3.3. Der Fragment-Output ist noch nicht automatisch das Pixel: er durchläuft danach Tests and Blending (Tiefentest, Blending).

Siehe Kapitel 6: Shaderprogrammierung.


Aufgabe 14 (Klausur-Niveau) - stride/offset bei drei Attributen + Zeichenbefehl-Wahl

Ein interleaved VBO speichert pro Vertex: Position (3 floats) + Normale (3 floats) + Texturkoordinate (2 floats).

  1. Berechne stride sowie den offset jedes der drei Attribute (in Bytes).
  2. Schreibe die drei glVertexAttribPointer-Aufrufe (Indizes 0, 1, 2) inklusive Aktivierung.
  3. Ein Modell aus 12 Dreiecken soll mit maximaler Vertex-Wiederverwendung gezeichnet werden. Welchen Zeichenbefehl wählst du, welche Buffer brauchst du, und wie gross ist der zugehörige count?
Lösung anzeigen

1. stride/offset (ein float = 4 Byte; 3+3+2=83 + 3 + 2 = 8 floats pro Vertex):

stride=8×4=32 Byte\text{stride} = 8 \times 4 = 32\ \text{Byte} offsetPos=0,offsetNormale=3×4=12,offsetTexCoord=6×4=24 Byte\text{offset}_{\text{Pos}} = 0, \quad \text{offset}_{\text{Normale}} = 3 \times 4 = 12, \quad \text{offset}_{\text{TexCoord}} = 6 \times 4 = 24\ \text{Byte}

2. Aufrufe:

glVertexAttribPointer(0, 3, GL_FLOAT, false, 32, 0);           // Position
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, false, 32, (void*)12);   // Normale
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, false, 32, (void*)24);   // TexCoord
glEnableVertexAttribArray(2);

3. Zeichenbefehl: Für maximale Vertex-Wiederverwendung nimmt man glDrawElements (indiziert). Nötige Buffer: VBO + VAO + IBO. Der count ist die Anzahl der Indizes:

count=3×12=36count = 3 \times 12 = 36
glBindVertexArray(vaoID);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);   // count = 36 Indizes
glBindVertexArray(0);

Zum Vergleich glDrawArrays (brute-force, sequenziell): braucht VBO + VAO, aber 3×12=363 \times 12 = 36 Vertices im VBO ohne Wiederverwendung, also mehr Datentransfer und keine geteilten Ecken.

Typischer Fehler: stride/offset in Elementen statt Bytes; Attribute nicht mit glEnableVertexAttribArray aktivieren; und count als 12 (Dreiecke) statt 36 (Indizes) angeben. Beachte auch: der IBO wird an das aktive VAO gebunden, deshalb glGenBuffers für den IBO erst nach glGenVertexArrays/glBindVertexArray.

Siehe Kapitel 4: OpenGL.


Aufgabe 15 (Klausur-Niveau) - Multiple Choice: gemischt

Kreuze jeweils die richtige(n) Aussage(n) an und korrigiere die falschen.

A) Bei glDrawElements(GL_TRIANGLES, count, ...) ist count die Anzahl der Dreiecke. B) uniform-Variablen sind pro Draw-Call konstant und READ-ONLY im Shader. C) layout(location = 2) wird von GLSL gegen die tatsächlichen VBO-Daten geprüft. D) Der Vertex-Shader ist optional, der Fragment-Shader ist Pflicht. E) v4.xgp ist ein gültiger Swizzle-Zugriff. F) Uniforms werden per Variablenname adressiert, Vertex-Attribute per Index.

Lösung anzeigen
  • A) Falsch. count ist die Anzahl der Indizes (=3×= 3 \times Dreiecke bei GL_TRIANGLES).
  • B) Richtig. uniform ist während des Rendervorgangs konstant und im Shader READ-ONLY.
  • C) Falsch. GLSL prüft layout(location = ...) nicht gegen die VBO-Daten. Der Programmierer muss selbst wissen, was das Attribut enthält.
  • D) Falsch. Beide sind Pflicht (Vertex und Fragment). Optional sind nur Tesselation- und Geometry-Shader.
  • E) Falsch. Die Sets .xyzw / .rgba / .stqp dürfen innerhalb eines Zugriffs nicht gemischt werden (x aus xyzw, g aus rgba, p aus stqp).
  • F) Richtig. Uniforms per Name (glGetUniformLocation), Vertex-Attribute per Index (layout(location = index) bzw. glVertexAttribPointer(index, ...)).

Richtig sind also B und F.

Tipp: Die häufigsten Klausur-Fallen bündeln sich hier: count-Definition, uniform-Rechte, kein layout-Typcheck, beide Pflicht-Shader, keine gemischten Swizzle-Sets, Name-vs-Index-Adressierung.

Siehe Kapitel 4: OpenGL und Kapitel 6: Shaderprogrammierung.