Aufgabe 3: Simple Lighting

Aus Nettundfroh
Wechseln zu: Navigation, Suche
Abbildung 1: Screenshot aus der WebGL-Implementierung

Inhaltsverzeichnis

Einleitung

Die Lösung der Aufgabe 3 bestand aus dem Ausbau einer Anwendung, die zur Abgabe für Aufgabe 2 vorgesehen war (Abgegeben wurde letztendlich ein anderer Lösungsansatz, der auf Lesson 4 des WebGL Tutorials basierte). Die Aufteilung der Anwendung in verschiedene Teilskripte, die saubere architektonische Ausführung und der bereits enthaltene Szenegraph waren auschlaggebend für die Erweiterung. Die Datei main.js ist Startpunkt der WebGL Anwendung.

Der Szenegraph ermöglicht die Anwendung der Transformationen auf das jeweils selektierte Objekt und ggf. inkludierte Kindobjekte. Darüber hinaus können jedem selektierten Objekt Shaderprogramme zugewiesen werden.

Aufgabe 3.1

Abbildung 2: Toonshader mit Abstufungen und Glanzlicht auf einer Torus-Primitiven.
  1. Anpassung der Anwendung an die TDL (Von der Erzeugung einer Kugel aus einem Kubus durch Tesselation zur Nutzung von TDL-Primitiven Sphere, Cube, Torus).
  2. Anpassung des Phong-Fragment-Shaders zur Darstellung von 4 Diskretisierungsstufen und Glanzlicht.
    1. Implementierung der Methode lambertToon(vec3 normal, vec3 lightDir, vec3 lightColor, vec3 surfaceColor, float steps):
      1. normal - wird beim Aufruf im Fragment-Shader mit der interpolierte Normalen belegt
      2. lightDir - der Vektor, der die Richtung der Lichtquelle beschreibt.
      3. lightColor - vec3 Variable, die die Lichtfarbe beschreibt und als Uniform-Variable dem Fragmentshader vorliegt.
      4. surfaceColor - die Farbe des Objektes auf das der Shader angewendet wird, übergeben als Uniform-Variable color.
      5. steps - Anzahl der Diskretisierungsstufen
      6. Die Farbe ergibt sich aus der Multiplikation von Oberflächen- und Lichtfarbe. Diese Multiplikation wird mit den Faktoren 0.2 und 0.8 ausgeführt und addiert, wodurch sich separate Farbanteile von 20 bzw. 80 Prozent ergeben. Die Diskretisierung wird durch die Multiplikation des größeren Farbanteils, der das diffuse Licht repräsentiert, mit einem Wert, der sich durch die Aufrundung des Skalarprodukts aus Interpolierten Normalen und dem Vektor für die Lichtrichtung multipliziert mit der Anzahl definierter Diskretisierungsschritte und anschließender Division durch die Diskretisierungsschritte ergibt, erreicht. Das Lambertlicht geht absichtlich zu 100% in die Gesamtfarbe eines Punktes ein, obwohl die Phongsche Reflektion hinzuaddiert wird, damit die Farben besonders kräftig wirken.
    2. Implementierung der Methode phongToonReflection(vec3 normal, vec3 lightDir, vec3 eyeDirection, vec3 specularClr, float size)
      1. normal, lightDir - siehe lambertToon
      2. eyeDirection - normalisierter Vektor für die Blickrichtung.
      3. specularClr - entspricht der Lichtfarbe, definiert in diesem Kontext die Farbe des Highlight.
      4. size - Abweichung, die die Größe des Highlight definiert (Schwellwert für Glanzlicht).
      5. Das Glanzlicht wird durch eine Modifikation der Phong Reflection erreicht. Eingangs wird die PhongReflection unter Einbeziehung von Blick-, Lichtrichtung und der interpolierten Normalen ermittelt. Ist der ermittelte Wert höher als der Schwellwert, wird die Lichtfarbe (specularClr) zurückgegeben und damit das Highlight.
    3. In der Main-Methode des Fragment-Shaders wird die Farbe des Pixels ermittelt. Die Farbe ergibt sich aus der Addition der Rückgabewerte der oben beschriebenen Methoden. Der Fragment-Shader setzt die ermittelte Farbe.
    4. Wechsel der Shader-Programme wird über Keylistener an den Nummerntasten ermöglicht.

Aufgabe 3.2

Abbildung 3: Toonshader mit Abstufungen und Glanzlicht mehrerer Lichtquellen auf einer Torus-Primitiven.
  1. Hinzufügen zusätzlicher Lichtquellen (Rot, Grün, Blau).
  2. Ergänzung der in der Aufgabenstellung geforderten Uniform Variablen als Arrays für Lichtposition, Farbe sowie den Zustand (An/Aus) der Lichtquelle. Zu diesem Zweck Implementierung eines Shader-Prekompilers, der mit '$' beginnende Variablen durch konstante Werte ersetzt, da GLSL-Schleifenbegingungen nur konstante Werte enthalten dürfen. Auf diese Weise ist es möglich, die Anzahl der Lichtquellen zu verändern. Geschieht dies innerhalb einer Scene, muss der entsprechende ShaderCode neu kompiliert werden.
  3. In der Main-Methode des Fragment-Shader werden nun die Werte aus den beiden Methoden über eine Schleife ermittelt deren Durchläufe sich an der Anzahl der Lichtquellen orientiert. In den Variablen lambertSum (Ergebnis aus lambertToon) und reflectionSum (Ergebnis aus phongToonReflection) werden die Ergebnisse aus den in 3.1 beschriebenen Methoden in den Durchläufen aufaddiert. Der Fragment-Shader setzt die Farbe, die sich aus der Addition der in der Schleife ermittelten Werte für lambertSum und reflectionSum ergibt.
  4. Implementierung von Bedienelementen für die Manipulation der Uniformvariablen.

Aufgabe 3.3

Abbildung 4: Toonshader mit Prozeduraler Textur auf einer Kubus-Primitiven.
  1. Verstehen des prinzipiellen Ablaufs eines Shaders, der eine prozedural erzeugte Textur nutzt.
  2. Erweiterung des PolkaDot Beispiels von Ian Romanick um die Projektion von Texturkoordinaten.
  3. Ergänzung der in der Aufgabenstellung geforderten Uniformvariablen für Radius (pointRadius), Dichte (pointDensity)und (pointColor) Farbe der Punkte.
  4. Implementierung eines neuen Fragment-Shaders für die prozedurale Textur.
    1. Zur Berechnung des sich wiederholenden Musters eignet sich die Modulooperation. Damit der Modulo Durchmesser (pointRadius*2) von Texturkoordinaten (Werte 0..1) sinnvoll berechnet werden kann, werden diese zunächst mit dem Durchmesser und pointDensity multipliziert. Vom Resultat wird pointRadius abgezogen um vom Mittelpunkt eines "Modulovierecks" auszugehen, dem 0-Punkt unseres neuen 2D-Punktkoordinatensystems. Das Skalarprodukt eines Punktes mit sich selbst ist in der Mitte 0, wenn der Punkt 0 ist. Je weiter entfernt ein solcher Punkt von der 0 (auch negativ) ist, umso größer ist das Skalarprodukt. Daher wird das Resultat dieser Berechnung als Schwellwert verwendet um entweder die Hintergrundfarbe oder die Punktfarbe zu zeichnen. Dies ist entweder mit einer If-Anweisung möglich oder mit einer Kombination aus mix- und step-Funktionsaufrufen. mix mischt zwei Farbwerte zu einem als drittes Argument übergebenen Verhältnis. step nimmt einen Schwellwert und einen anderen Wert entgegen, der hier mit dem zuvor berechneten Skalarprodukt belegt wird. Der Schwellwert wird konstant als 400 definiert. step gibt entweder 0 oder 1 zurück und setzt somit ein einseitiges Mischverhältnis ohne Verläufe der beiden Farbwerte abhängig von der verrechneten Texturkoordinatenposition.
    2. Die Implementierung der Lichtberechnung unterscheidet sich bis auf die zuvor beschriebene Berechnung der Ausgangfarbe nicht von dem in 3.2 beschriebenen Toon-Shader.
  5. Implementierung zusätzlicher Bedienelemente zur direkten Manipulation der Werte der Uniformvariablen.

Lösung

WebGL Implementierung

Quellen

Fragment Shader Introduction by Ian Romanick

ShaderToy

GLSL Sandbox








Zurück zur Real-Time Rendering Hauptseite

Master Semester 2