CGExercises

Exercise #08

Computergraphik Übungsblatt #08


OpenGL Tutorial: Shader



Aufgabe 8.1: Shader Editor

Starten Sie mit Ihrem Code aus der vorhergehenden Übung #07.

Ergänzen Sie den Code um einen Shader bzw. bauen Sie in Ihren Code einen Shader-Editor ein. Dazu benötigen Sie die folgenden zusätzliche Zeilen:

Im Globalen Namensraum:

GLuint prog_id;
const char shader[] = "";

In der Methode initializeOpenGL():

prog_id = lglCompileGLSLProgram(shader);
create_lgl_Qt_ShaderEditor("shader", &prog_id);

In der Methode renderOpenGL():

lglUseProgram(prog_id, false);

Sie sollten nun eine unbeleuchtete (und untexturierte) Szene sehen. Der Vertex Shader multipliziert nur die Vertices mit der MVP (die mit lglModelView gesetzt wurde). Und der Fragment Shader verwendet nur die aktuell spezifizierte Farbe (die zuletzt mit lglColor gesetzt wurde).

D.h. es wird der einfachste denkbare Shader - der sog. Plain-Shader - verwendet (siehe Cheat Sheet → Shaders).

Im Folgenden werden wir nun Schritt für Schritt diesen Shader weiterentwickeln, so dass die Szene wieder beleuchtet dargestellt wird. Editieren des Shaders im Editor Fenster erfolgt wie folgt:

  • Der aktuell editierte Shader wird benutzt
  • Save & Quit merkt sich den aktuellen Shader
  • Commit → Abspeichern des Shaders in den C++ Code

Zur Erinnerung vorher noch ein paar Verständnisfragen:

  • Welche Daten werden im Vertex- bzw. Fragment-Shader verarbeitet?
  • In welchem Koordinatensystem befindet man sich im Vertex- bzw. Fragment-Shader?
  • Wo findet man den Vertex- bzw. Fragment-Shader im GLSL Shader-Editor?

Aufgabe 8.2: GLSL Fog


Non-Linear Fog

Wir steigen mit einem weiteren einfachen GLSL Shader ein: Fogging! D.h. verwenden Sie den folgenden Fragment Shader:

#version 120
uniform vec4 color;
void main()
{
   const float density = 0.01f;
   float z = 1.0f / gl_FragCoord.w;
   float f = 1.0f - exp(-3 * density * z*z*z);
   gl_FragColor = (1.0f-f)*color + f*vec4(1);
}

Ändern Sie die Hintergrundfarbe, damit diese zur Darstellung durch den Shader passt. Ändern Sie die Dichte density so dass sie einen passenden Farbverlauf erhalten.

Aufgabe 8.3: GLSL Uniform


glVertex Cheat Sheet

Ersetzen Sie die Konstante density im GLSL Shader durch einen uniformen Parameter, den Sie im C++ Hauptprogramm bestimmen können (via lglUniformf(“density”, value)). Verwenden Sie wie in Übung #06 passende Tasten, um den Parameter zu verändern.

Aufgabe 8.4: GLSL Varying

Momentan wird die Szene noch einfarbig pro Objekt gezeichnet, d.h. es gibt keinerlei Farbvariation. Diese bringen wir jetzt ins Spiel:

Transportieren Sie die Vertices aus dem Vertex- in den Fragment-Shader, indem Sie die Koordinaten im Vertex-Shader in ein sog. Varying schreiben. Wir verwenden die unveränderten Objekt-Koordinaten, d.h. es wird nicht mit der MVP multipliziert!


Objekt-Koordinaten als Fragment-Farbe

Diese Objekt-Koordinaten lesen wir nun im Fragment-Shader aus dem Varying aus und verwenden sie als Fragment-Farbe.

Eventuell müssen die Farbwerte etwas angepasst werden, um eine leicht psychedelische Darstellung (wie rechts beispielhaft abgebildet) zu erreichen. Dazu multipliziert man die einzelnen Komponenten mit einer Konstante und verwendet nur den Nachkommaanteil (GLSL: fract).

Hinweis: Für diese und die folgenden Aufgaben sind keine Änderungen am C++ Programm erforderlich, lediglich der GLSL Shader ist anzupassen.

Aufgabe 8.5: GLSL Attribute (Normalen)

Transportieren Sie nun nicht nur die Vertices sondern auch die Normalen aus dem Vertex- in den Fragment-Shader. D.h. schreiben Sie das Attribut vertex_normal in ein zusätzliches Varying.

Aufgabe 8.6: GLSL “Debugging”

Jetzt wird es noch psychedelischer: Verwenden Sie die Normalen für die Fragment-Farbe. Aber nicht die tatsächlichen Normalen, sondern wir verwenden die folgende Abbildung:

$f(\vec{n}) = 0.5\cdot\vec{n} + (0.5, 0.5, 0.5)^T$

Auf diese Weise können wir die Normalen “lesen” und Fehler erkennen → Graphisches Debugging.

Wir erkennen dadurch, dass die Normalen nicht konsistent zwischen den einzelnen Robotersegmenten sind: Welche Normale bzw. welche Farbe müsste eine Fläche tatsächlich haben, auf die der Betrachter frontal schaut? Bestimmen Sie den konkreten RGB-Farbwert! Tipp: himmelblau.

Aufgabe 8.7: GLSL Normalentransformation

Erinnern Sie Sich, dass die Normalen im Vertex-Shader mit einer speziellen Matrix multipliziert werden müssen? Verwenden Sie diese (siehe Cheat Sheet → GLSL)!

Renormalisieren Sie außerdem die Normalen im Fragment-Shader (GLSL: normalize)!


Ambiente Beleuchtung

Diffuse Beleuchtung

Aufgabe 8.8: GLSL Shading

Zum Abschluß können wir die Normalen nun für die Beleuchtung der Objekte verwenden. Die am einfachsten zu berechnende Beleuchtung ist die diffuse lokale Beleuchtung:

Die diffuse Beleuchtung verwendet den Cosinus des Zwischenwinkels von Lichtvektor $\vec{l}$ und Normale $\vec{n}$ als Beleuchtungsintensität bzw Helligkeit. Dazu muss das Skalarprodukt der Normalen mit dem Lichtvektor berechnet werden. Als Lichtvektor wählen wir einen beliebigen normalisierten Lichtrichtungsvektor als Beleuchtungsrichtung in Augenkoordinaten für eine rein direktionale Lichtquelle. Das Ergebnis der Berechung ist die Intensität $I_d = \vec{n} \cdot \vec{l}$ des diffusen Anteils des lokalen Blinn-Phong Beleuchtungsmodells. Mit dieser Helligkeit modulieren (d.h. multiplizieren) wir nun die bisherige Vertex-Farbe (color). Achtung: $I_d$ sollte nicht negativ werden (GLSL: max)!


Ambiente & Diffuse Beleuchtung

Verwenden Sie außerdem einen ambienten bzw. konstanten Beleuchtungsanteil $I_a = const$. Für einen warmen Beleuchtungston, wie er z.B. durch die Sonne erzeugt wird, verwendet man $I_a$ = (0.2, 0.1, 0), den man hinzuaddiert.

Aufgabe 8.9: Toon Shading (Optional, Bonuspunkte ++)

Anstelle einer physikalisch motivierten, diffusen Beleuchtung erzeugen wir jetzt einen Comic-Look.

Beim so genannten Toon Shading (Cell bzw. Tone Shading oder eben auch Comic Shading) werden nur wenige Farben einer festen Farbpalette benutzt, um die Beleuchtungsintensität darzustellen.


Toon Shading

Am Roboter ist das eventuell nicht so schön zu erkennen. Stellen Sie daher neben den Roboter noch einen Teapot (lglTeapot).

Benutzen Sie jetzt das Skalarprodukt (die vorher berechnete Intensität $I_d$), um anhand einer Fallunterscheidung (if-else-Kaskade) folgende Farben zu verwenden:

  1. (1.0 1.0 1.0) im Bereich [0.98 .. 1.0]
  2. (0.7 0.3 0.3) im Bereich [0.7 .. 0.98]
  3. (0.5 0.15 0.15) im Bereich [0.4 .. 0.7]
  4. (0.3 0.1 0.1) im Bereich [0 .. 0.4]
  5. (0.1 0.1 0.1) im Bereich [−1 .. 0]


Hausaufgaben bis zum neunten Praktikum


1. BRDF:
Zeichnen Sie die BRDF von einer Spiegelkugel, einer Plastikkugel und einer schwarzen und einer weißen matten Kugel (analog zu den Illustrationen in der Vorlesung)!

2. Lokale Beleuchtung:

  1. Zeichnen Sie den Lichtweg für die lokale Beleuchtung mittels Blinn-Phong. Tragen Sie alle relevanten Vektoren bzw. Größen ein und beschreiben Sie diese stichwortartig.
  2. Was ist der Unterschied zwischen Gouraud, Phong und Blinn-Phong?
  3. Beim Würfel werden die einzelnen Seiten ja flach dargestellt. Können Sie die Seiten auch einfach mit Hilfe von Flat Shading korrekt wiedergeben? Warum? Und unter welchen Bedingungen?
  4. Wir haben als Abschwächungsfunktion für eine positionale Lichtquelle das Quadrat des Abstandes kennen gelernt, da physikalisch gesehen das die einzige richtige Abschwächung darstellt. D.h., als Faktor für den Einfluss des Lichts ergibt sich etwas wie $\frac{1}{c+|\vec{l}|^2}$ mit $c = const$, $\vec{l}$ = Lichtvektor. In der Praxis möchte man sicher gehen, dass eine Lichtquelle keinen Einfluss auf Geometrie jenseits eines gewissen Abstandes $maxdist$ hat. Wie kann z.B. eine lineare Abschwächungsfunktion aussehen, die am Ort der Lichtquelle den Einfluß 1 hat, der bis zum Abstand $maxdist$ auf 0 abfällt, und dann auch nicht negativ wird? Zeichnen Sie erst diese Funktion schematisch und überlegen Sie Sich anhand der Zeichnung die passende Formel bzw. Geradengleichung.

3. Globale Beleuchtung:
Zeichnen Sie beispielhaft die Lichtwege, die für die folgenden globalen Beleuchtungsmodelle relevant sind:

  • Raytracing
  • Radiosity
  • Ambient Occlusion
  • Monte-Carlo

Nehmen Sie an, dass Ihre Szene aus einem Raum mit zwei Plastikwürfeln besteht und zeichnen Sie jeweils die entsprechenden Lichtpfade. Zeichnen Sie der Einfachheit halber nicht dreidimensional.

4. Optional: Kaustik
Ganz dumm gefragt: Wieso lassen sich Kaustiken weder mit Raytracing noch mit Radiosity darstellen? Was ist überhaupt eine Kaustik? Begründen Sie Ihre Antwort zeichnerisch!

Options: