shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarer/shaderbeispiele... · william donnelly:...

49
Fachbereich 4: Informatik Seminar Echtzeit-Rendering SS 2008 Shaderbeispiele vorgelegt von Elisa Ziegler und Alexander Ehrhardt Betreuer: Dipl.-Inform. Jakob B¨ arz (Institut f ¨ ur Computervisualistik, AG Computergrafik) Koblenz, 17. Juli 2008

Upload: others

Post on 14-Sep-2019

12 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

Fachbereich 4: Informatik

Seminar

Echtzeit-Rendering

SS 2008

Shaderbeispiele

vorgelegt von

Elisa Ziegler und Alexander Ehrhardt

Betreuer: Dipl.-Inform. Jakob Barz(Institut fur Computervisualistik, AG Computergrafik)

Koblenz, 17. Juli 2008

Page 2: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

Contents

1 Motivation 3

2 Shader Allgemein 32.1 OpenGL-Pipeline . . . . . . . . . . . . . . . . . . . . . . . . . . 32.2 Vertex-Shader . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42.3 Fragment-Shader . . . . . . . . . . . . . . . . . . . . . . . . . . 42.4 Wahl des Shaders . . . . . . . . . . . . . . . . . . . . . . . . . . 52.5 OpenGL Shading Language . . . . . . . . . . . . . . . . . . . . 6

2.5.1 Uniforme Daten . . . . . . . . . . . . . . . . . . . . . . 62.5.2 Varying Daten . . . . . . . . . . . . . . . . . . . . . . . 62.5.3 Minimaler Vertex-Shader . . . . . . . . . . . . . . . . . . 62.5.4 Minimaler Fragment-Shader . . . . . . . . . . . . . . . . 7

3 Wolken-Shader 73.1 Wolkenreprasentation . . . . . . . . . . . . . . . . . . . . . . . . 73.2 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

3.2.1 Implementation des Wolken-Shaders . . . . . . . . . . . . 93.3 Beleuchtung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

4 Wasser-Shader 114.1 Wellengenerierung . . . . . . . . . . . . . . . . . . . . . . . . . 12

4.1.1 Hohenfeld . . . . . . . . . . . . . . . . . . . . . . . . . . 124.1.2 Displacement Mapping . . . . . . . . . . . . . . . . . . . 124.1.3 Generierung des Hohenfelds . . . . . . . . . . . . . . . . 13

4.2 Zerlegung der Oberflache . . . . . . . . . . . . . . . . . . . . . 144.3 Optische Simulation . . . . . . . . . . . . . . . . . . . . . . . . . 15

4.3.1 Reflexion . . . . . . . . . . . . . . . . . . . . . . . . . . 164.3.2 Refraktion . . . . . . . . . . . . . . . . . . . . . . . . . 174.3.3 Brechende Wellen . . . . . . . . . . . . . . . . . . . . . 18

4.4 Rendern der Wasseroberflache . . . . . . . . . . . . . . . . . . . 19

5 Einleitung des praktischen Teils 19

6 Formatierungen 19

7 Voraussetzungen fur dieses Projekt 207.1 Bibliotheken . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

8 Die Klasse ShaderContainer 208.1 Beschreibung . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208.2 Benutzung der Klasse ShaderContainer . . . . . . . . . . . . . . 208.3 Aufgabe der Funktion setShaders . . . . . . . . . . . . . . . . 22

1

Page 3: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

9 Grober Aufbau des Projekts 23

10 Die verwendeten Shader 24

11 Der Partikelshader 2411.1 Ziele des Partikelshaders . . . . . . . . . . . . . . . . . . . . . . 2511.2 Partikelverhalten . . . . . . . . . . . . . . . . . . . . . . . . . . 25

11.2.1 Suche nach einer Weg- Zeitfunktion . . . . . . . . . . . . 2511.3 Benotigte Daten pro Partikel . . . . . . . . . . . . . . . . . . . . 2711.4 Schematischer Aufbau des Partikelsystems . . . . . . . . . . . . . 2811.5 Erstellung der Attributdaten . . . . . . . . . . . . . . . . . . . . 2811.6 ”Hochladen” der erstellten Daten in den Shader . . . . . . . . . . 29

11.6.1 ”Hochladen“ der globalen Zeit . . . . . . . . . . . . . . . 2911.6.2 ”Hochladen” der built-in Attribute . . . . . . . . . . . . . 3011.6.3 ”Hochladen” der benutzerdefinierten Attribute . . . . . . 3111.6.4 Die gesamte Zeichenmethode des Konfettipartikelshaders 31

11.7 Der Vertexshader . . . . . . . . . . . . . . . . . . . . . . . . . . 3311.8 Der Fragmentshader . . . . . . . . . . . . . . . . . . . . . . . . . 34

12 Refraktion und Reflexion 3412.1 Fresnel-Effekt . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3412.2 Vereinfachendes Modell . . . . . . . . . . . . . . . . . . . . . . 3512.3 Schematischer Aufbau des Reflexion/Refraktionssystems . . . . . 3712.4 Ursache der Kamera-zu-Welt-Matrix . . . . . . . . . . . . . . . . 38

12.4.1 Bestimmung der Kamera-zu-Welt-Matrix (fur Vektoren) . 3912.5 Erzeugung einer dynamischen Cubemap . . . . . . . . . . . . . . 3912.6 ”Hochladen” der Cubemap . . . . . . . . . . . . . . . . . . . . . 4212.7 ”Hochladen” der restlichen Variablen . . . . . . . . . . . . . . . 4312.8 Der Vertexshader . . . . . . . . . . . . . . . . . . . . . . . . . . 4312.9 Der Fragmentshader . . . . . . . . . . . . . . . . . . . . . . . . . 44

13 Was ist mit dem Projekt noch moglich 45

14 Bekannte Probleme 46

15 Fazit 46

2

Page 4: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

1 Motivation

Die Programmierung der Graphics Programming Unit, kurz GPU, mittels Shadernerweitert die Moglichkeiten des Programmierers deutlich. Ist es bei einer fixedfunction Pipeline nur moglich neue Effekte durch Erweiterung des ApplicationProgrammer Interfaces (API) hinzuzufugen, erhalt der Programmierer nun Frei-heiten, die es ihm ermoglichen neue Effekte selbst zu generieren und seiner App-likation ein einzigartiges Aussehen zu verleihen.1 Es ist nun moglich die Pipelinezu programmieren und auf den Verarbeitungsprozess von Eckpunkten, Fragmentenoder auch Primitiven gezielt Einfluss zu nehmen.

Die Grafikhardware kann durch ihre Flexibilitat auch komplexe Aufgaben bear-beiten. Anspruchsvolle 3D-Applikationen, wie sie inzwischen gang und gabe sind,waren mit den bisherigen Moglichkeiten kaum in Echtzeit zu realisieren. Zum Ver-wenden von Techniken wie Bump- und Displacement-Mapping und zum Simulierennaturlicher Effekte wie Feuer, Rauch, Wasser oder auch zum Rendern von Haarensind frei programmierbare Shader eine große Hilfe.

2 Shader Allgemein

Shader sind kleine Programme, die speziell auf die GPU abgestimmt sind. Siesind dazu bestimmt auf der GPU in Echtzeit zu laufen. Mit diesem Ziel sind sieentworfen worden. Shader nutzen also die von der GPU gebotene Geschwindigkeitund ihre Verarbeitungsmoglichkeiten.

2.1 OpenGL-Pipeline

Shader konnen einzelne Teile der fixed function Pipeline umgehen, diese ersetzenoder deren Funktionalitat erganzen. Wie in der Abbildung 1 zu sehen ist, existierenunterschiedliche Arten von Shadern, die unterschiedliche Teile der Pipeline erset-zen.

Vertex-Shader, die fur jeden Eckpunkt aufgerufen werden, konnen an Stelle derTransformation mit Modelview-Matrix und Projection-Matrix aufgerufen werden.Auf Vertex-Shader wird im Abschnitt 2.2 naher eingegangen.

Geometry-Shader, die auf Grafikprimitiven also zum Beispiel Linien oder Drei-ecken arbeiten, werden nach der Ausfuhrung samtlicher Vertex-Shader aufgerufen.Auf sie wird in dieser Ausarbeitung nicht naher eingegangen, da im Rahmen desSeminars ein eigenstandiger Vortrag zum Thema der Geometry-Shader gehaltenwurde.

Ganz am Ende der Pipeline, auf der nach der Viewport Transformation erzeugtenAusgabe arbeiten Fragment-Shader, die fur jedes einzelne Fragment aufgerufenwerden. Da aus einem Fragment ein Pixel entsteht, werden Fragment-Shader auchals Pixel-Shader bezeichnet. Mit ihnen beschaftigt sich der Abschnitt 2.3.

1vgl. [Fos03],S.89

3

Page 5: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

Figure 1: OpenGL-Pipeline, in der die Bereiche markiert sind, die durch Shader ersetztwerden konnen

2.2 Vertex-Shader

Ein Vertex-Shader wird fur jeden Eckpunkt einmal aufgerufen und arbeitet zueinem Zeitpunkt nur auf einem Eckpunkt. Fur diesen Eckpunkt kontrolliert einVertex-Shader, wie er beleuchtet und transformiert wird. Ein Vertex-Shader verfugtuber keine Informationen bezuglich der Topologie und kann somit auch nur denEckpunkt, auf dem er gerade arbeitet, beeinflußen. Außerdem ist es einem Vertex-Shader nicht moglich Punkte zu erzeugen oder zu loschen.

Um die Funktionalitat der Transformation des eingehenden Punkts mit derModelview-Matrix und Projection-Matrix ersetzen zu konnen, erhalt ein Vertex-Shader als Eingabedaten alle Informationen, die auch in die Pipeline am Anfangeingehen, also fur jeden Eckpunkt die Position, die Farbe, die Texturkoordinate unddie Normale. Auch konnen fur den Eckpunkt einem Vertex-Shader benutzerdefinierteAttribute ubergeben werden. Ein Vertex-Shader muss als Ausgabe den Eckpunktin homogenen Clipkoordinaten liefern, also die Position im kanonischen Volumenvon -w bis w. Um dies gewahrleisten zu konnen, kann ein Vertex-Shader aufOpenGL-Zustande zugreifen. Außerdem kann er auf den Texturspeicher zugreifenund uniforme2, benutzerdefinierte Daten erhalten. Abgesehen von der Positionim kanonischen Volumen, kann ein Vertex-Shader als weitere Ausgabe die Farbe,Texturkoordinate und benutzerdefinierte Attribute bestimmen.

2.3 Fragment-Shader

Ein Fragment-Shader wird fur jedes zu zeichnende Pixel aufgerufen, arbeitet ana-log zu Vertex-Shadern aber stets nur auf einem isolierten Fragment3. AnderePixel im Framebuffer konnen nicht bearbeitet werden. Ein Fragment-Shader kann

2Auf diese uniformen Variablen wird im Abschnitt 2.5 genauer eingegangen.3Die Bezeichnung Fragment beschreibt hierbei die Daten, die uber ein noch nicht verarbeite-

tes Pixel vorliegen. Diese Daten enthalten auch alle Informationen, die zur im Fragment-Shadervorgenommenen Farbberechnung gebraucht werden, die dem Fragment-Shader also als Eingabeubergegeben werden.

4

Page 6: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

allerdings entscheiden, ob ein Fragment gezeichnet und wie Texturen angewen-det werden sollen. Hierzu ist ein wahlfreier Zugriff auf den Texturspeicher notigund moglich. Außerdem kann ein Fragment-Shader wie der Vertex-Shader aufOpenGL-Zustande und uniforme, benutzerdefinierte Daten zugreifen. Als Eingabeerhalt er fur jedes Fragment einen interpolierten Farbwert, interpolierte Texturko-ordinaten und interpolierte benutzerdefinierte Attribute. Als Ausgabe muss einFragment-Shader die Farbe des Pixels bestimmen. Dies ist meist auch die alleinigeAusgabe, auch wenn es moglich ist, den Tiefenwert ebenfalls auszugeben.

2.4 Wahl des Shaders

Da mit Vertex- und Fragment-Shadern zwei verschiedene Shadertypen zur Ver-fugung stehen, muss entschieden werden, welcher Teile eines Algorithmus mitwelchem Shader implementiert werden soll, wobei es nicht notig ist, dass beideArten von Shadern vorhanden sind. Es ist auch moglich nur einen Fragment- oderVertex-Shader zu implementieren oder mehrere Shader eines Typs.

Zur Bestimmung welcher Shader Verwendung finden soll, kann als Richtliniegelten, dass Berechnungen, dernen Eingabedaten sich stark und schnell verandernoder deren Resultate stark variieren, eher fur einen Fragment-Shader geeignet sind.Ein Beispiel hierfur ist die Beleuchtung einer glanzenden Oberflache. Fande diesein einem Vertex-Shader statt, musste zwischen den sich ergebenden Werten bili-near interpoliert werden, wodurch Artefakte zustande kamen. Außerdem konntenGlanzpunkte verloren gehen.4 Andern sich die Daten, auf denen der Shader ar-beitet, hingegen kaum, wie es bei der Beleuchtung von Objekten mit diffuserOberflache der Fall ist, kann die Implementation gut in einem Vertex-Shader statt-finden.

Im Prinzip muss eine Wahl zwischen hoherer Qualitat oder schnellerer Aus-fuhrung getroffen werden: Eine hohere Qualitat wird durch Verwendung einesFragment-Shaders erreicht, ein Vertex-Shader kann jedoch schneller sein. Diemoglicherweise vorhandene Uberlegenheit eines Vertex-Shaders gegenuber einemFragment-Shaders in Bezug auf die Geschwindigkeit kommt dadurch zustande,dass ein sehr starkes Ungleichgewicht zwischen der Anzahl der Eckpunkte und derFragmente besteht. Es existieren zwar aus diesem Grund mehr Fragmentprozes-soren als Vertexprozessoren auf den Grafikkarten5, aber trotzdem kann die Ver-arbeitung aller Fragmente mehr Zeit in Anspruch nehmen als eine entsprechendeVerarbeitung aller Eckpunkte.6

4Dies ist vergleichbar mit dem optischen Unterschied zwischen Gouraud- und Phong-Shading,wenn die Eckpunkte eines Primitivs die selbe Farbe haben. Naheliegenderweise musste man auch beiPhong-Shading die entscheidenden Berechnungen in einem Fragment-Shader vornehmen. Gouraud-Shading kann hingegen problemlos komplett von einem Vertex-Shader ubernommen werden.

5vgl. William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05],S. 125

6Das mehr Fragmentprozessoren als Vertexprozessoren vorhanden sind, andert sich nun durchEinfuhrung von universell einsetzbaren unified Shadern, da diese erst durch das Programm ihrenFunktionsumfang zugewiesen bekommen.

5

Page 7: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

2.5 OpenGL Shading Language

Die OpenGL Shading Language, kurz GLSL, besitzt viele fur Hochsprachen ty-pische Eigenschaften. So ist das Erstellen von Subroutinen moglich, die Daten-typen sind auf das Anwendungsgebiet abgestimmt und es existieren Mechanismenzur Flußkontrolle. Die Syntax von GLSL orientiert sich an C++. Die Ausgabeder Shader-Programme findet uber vordefinierte Ausgabevariablen statt, gleichesgilt fur die Eingabedaten, die pro Vertex beziehungsweise pro Fragment ubergebenwerden.

Zwei besondere im Kontext der Shader-Programmierung verwendete Sprach-elemente sind uniforme und varying Daten.

2.5.1 Uniforme Daten

Die Bezeichnung uniform kennzeichnet Variablen, die der Weitergabe von Datenvon der Applikation an die Shader dienen. Sie sind unveranderlich wahrend derAusfuhrung des Shaderprogramms, konnen also vom Shader selbst nicht beeinflußtwerden. Die Modelview- und Projectionmatrix sind beispielsweise in Shadern uberuniforme Variablen zuganglich, gleiches gilt fur Informationen uber die existieren-den Lichtquellen.

2.5.2 Varying Daten

Daten, die von einem Shader zum anderen, also von einem Vertex-Shader an einenFragment-Shader weitergegeben werden sollen, werden durch die Bezeichnungvarying gekennzeichnet. Varying referiert hierbei auf die Tatsache, dass die Datenvon einem Vertex-Shader auf Basis eines Eckpunkts erstellt werden, von einemFragment-Shader allerdings fur ein Fragment gelesen werden. Die in einem Vertex-Shader in varying Variablen geschriebenen Daten werden also vor ihrer Verwen-dung in einem Fragment-Shader interpoliert.

2.5.3 Minimaler Vertex-Shader

Einer der einfachsten in GLSL verfassten Vertex-Shader konnte folgendermaßenaussehen:

void main(){gl_Position = gl_ModelViewProjectionMatrix*gl_Vertex;gl_FrontColor = gl_Color;

}

Dieser Vertex-Shader transformiert den aktuellen Eckpunkt in Clipkoordinaten,indem er die in gl Vertex ubergebende Position des Eckpunkts mit der akku-mulierten Modelview- und Projection-Matrix, die dem Shader in Form der einge-bauten uniform Variable gl ModelviewProjectionMatrix zur Verfugungsteht, multipliziert. Das Ergebnis wird in die fur die Position zur Verfugung steh-ende Ausgabevariable gl Position geschrieben. Außerdem wird der Farbe,

6

Page 8: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

die ausgegeben wird, also gl FrontColor, die fur den Eckpunkt ubergebeneFarbe gl Color zugewiesen. gl Color und gl Vertex sind eingebaute Eck-punktattribute, die in Vertex-Shadern immer verfugbar sind. gl Position undgl FrontColor sind zwei der speziellen Ausgabevariablen, die Vertex-Shaderbesitzen. Sie dienen der Ausgabe der transformierten Position und der Eckpunkt-farbe.

2.5.4 Minimaler Fragment-Shader

Ein minimaler in GLSL verfasster Fragment-Shader konnte so aussehen:

void main(){gl_FragColor = gl_Color;

}

Hierbei handelt es sich um einen Shader, der nur der Bedingung, die an einenFragment-Shader gestellt wird genugt: Fur jedes Fragment wird eine Farbe gener-iert. In diesem Beispiel geschieht dies auf die einfachste denkbare Weise: DerAusgabevariable gl FragColor wird der dem Shader ubergebene interpolierteFarbwert gl Color zugewiesen.

3 Wolken-Shader

Anders als in der traditionellen Computergraphik, die eher mit Oberflachen ar-beitet, handelt es sich bei Wolken um Volumina. Doch auch Volumen sind immeran ein geometrisches Primitiv gebunden, es muss immer ein Objekt im Hinter-grund vorhanden sein.7 Das Volumen selbst entspricht dann einer an das Primitivgebundenen Atmosphare. Diese Atmosphare wird in diesem Beispiel durch einenVolumen-Shader implementiert, der es zum Ziel hat realistisch aussehende Wolkenzu rendern. Das hierzu verwendeten Verfahren stutzt sich auf Jesse Laeuchlis Im-plementation und Vorstellung eines Wolken-Shaders8, das auf einem einfachenblauen Hintergrund Ergebnisse wie beispielsweise in Abbildung 2 zu sehen, liefert.Bei der hier dargelegten Methode zur Darstellung von Wolken wird besonders da-rauf Wert gelegt, dass Moglichkeiten geboten werden die Struktur und Form derWolke kontrollieren zu konnen.

3.1 Wolkenreprasentation

Um einen Wolken-Shader aufbauen zu konnen, muss man sich zunachst uber dieReprasentation der Wolken Gedanken machen. Dies kann durch eine modifizierteimplizite Gleichung

F (x, y, z) = (x− Cx)2 + (y − Cy)2 + (z − Cz)

2 = r

7vgl. [Apo00], S.3148Jesse Laeuchli: Volumetric Clouds. In: [Eng05], S.611-616

7

Page 9: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

Figure 2: Beispielhafte Wolkendarstellung erzeugt mit dem vorgestellten Wolken-Shader

geschehen.9 Wird diese Gleichung mittels eines Volumenrenderingsystems

ausgewertet, ist das Ergebnis eine Kugel mit dem Mittelpunkt C =

Cx

Cy

Cz

und

dem Radius r.10 Die Funktion beschreibt dann die Dichte der Wolke an einemgegebenen, durch x, y und z definierten Punkt. Zum Beeinflußen der Parameterdieser Dichtefunktion wird die fractional Brownian motion (fBm)11 verwendet.

9Die Verwendung anderer impliziter Gleichungen, die nicht wie die hier verwendete eine Kugelsondern ein anderes geometrisches Objekt beschreiben, ist ebenfalls moglich und fuhrt zu analogenErgebnissen.

10vgl. Jesse Laeuchli: Volumetric Clouds. [Eng05], S.61111Bei der fraktalen Brownschen Bewegung handelt es sich um einen kontinuierlichen Gaußprozess

mit Mittelwert 0. Auch bekannt ist sie als ”Random Walk Process“, da vom Prinzip her Schritte

8

Page 10: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

Das Ergebnis wird mittels Volumenrendering visualisiert.Um die Struktur der Wolke zusatzlich zu verandern und zu beeinflußen, konnen

mehrere implizite Gleichungen mit unterschiedlichen Radii oder eine impliziteGleichung mit einer Turbulenzfunktion vermischt werden. Es wird jeweils eineGewichtung vorgenommen, die besagt, wie stark eine implizite Gleichung oderTurbulenzfunktion in das Ergebnis eingehen soll. Bei einer Turbulenzfunktion han-delt es sich um eine beliebige Rauschfunktion.

3.2 Implementation

Bevor man den Shader selbst implementieren kann, muss ein Volumenrenderingsys-tem implementiert und eine Rauschfunktion generiert und gespeichert werden.

Das Volumenrenderingsystem arbeitet, indem es mehrere Quadrate von hintennach vorne senkrecht zur Blickrichtung zeichnet. Die Quadrate liegen also von derKamera aus auf der z-Achse, wobei das zuerst gezeichnete am weitesten weg vomBetrachter liegt und das zuletzt gezeichnete dem Betrachter am nachsten ist. Jemehr Quadrate im Volumenrenderingsystem verwendet werden, desto besser siehthinterher das Ergebnis aus. Auf die gezeichneten Quadrate wird eine Alphatexturangewendet.

Da es sehr aufwendig werden kann Rauschen in Shadern zu erzeugen, beson-ders wenn man Rauschen fur jedes Pixel generieren will, wird dies vor Aufruf desShaders in der Applikation erledigt. Das dabei generierte Rauschen wird dann ineine Textur gespeichert und dient spater im Shader als Turbulenzfunktion. Da derSpeicher beschrankt ist, kann diese Textur nur endlich groß sein, was bei ihrerAnwendung zu Artefakten fuhren kann. Aus diesem Grund muss die Textur anden Randern so bearbeitet werden, dass man sie nahtlos immer wieder aneinanderhangen kann.

3.2.1 Implementation des Wolken-Shaders

Ist die Rauschfunktion berechnet und das Volumenrenderingsystem erstellt, kannder Shader zu arbeiten beginnen. Da keine guten Ergebnisse zu erwarten sind,wenn man nur an den Eckpunkten der Quadrate eine Berechnung vornimmt undzwischen den Ergebniswerten interpoliert, wird ein Fragment-Shader implemen-tiert. Besteht der Wunsch zusatzlich zur Rauschfunktion eine weitere Kontroll-moglichkeit der Wolkenstruktur hinzufugen, kann wie bereits erwahnt eine weitereimplizite Gleichung berechnet und mit der bereits generierten vermischt werden.

Die folgenden Schritte geben wieder, was im Shader konkret berechnet wird:

1. Erstellen des fBm-Fraktals

einer bestimmten Lange in eine zufallige Richtung gemacht werden. Der Schrittlange liegt ein furdie entstehende Bewegung charakteristischer Wert zugrunde. Die Bezeichnung als fraktal resultiertaus der Tatsache, dass, wenn man an eine beliebige Stelle der Funktion bzw. ihrer Darstellung naherherangeht, diese Stelle immer ein ahnliches Aussehen aufweist, wie das, was man zuvor gesehen hat.

9

Page 11: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

2. Skalieren der fBm-Funktion

Diese Skalierung ermoglicht es die Struktur der Wolken besser beeinflußenzu konnen.

3. Addition der fBm-Funkktion auf die Eingabeparameter x,y und z der im-pliziten Gleichung

4. Generieren der impliziten Funktion d

Fur den Mittelpunkt C =

Cx

Cy

Cz

ergibt sich:

float d=sqrt((point.x-C.x)*(point.x-C.x)+(point.y-C.y)*(point.y-C.y)+(point.z-C.z)*(point.z-C.z));

Point ist hierbei der Vektor, der die gemaß Schritt 3 veranderten Eingabepa-rameter enthalt. Im tatsachlichen Shader wurde man fur den Mittelpunkt Callerdings konkrete Werte festlegen oder mittels eines uniformen Parametersubergeben und den so gegebenen Mittelpunkt in die Formel einsetzen.

5. Ergebnis d wird mit der Turbulenzfunktion vermischt

Hierzu wird auf die gekachelte Textur zugegriffen. Je starker die Rauschw-erte in die Mischung eingehen, desto turbulenter erscheint die Wolke. Gehensie nur zu geringen Teilen ein, wird die Wolke ein strukturierteres Aussehenannehmen.

6. Skalierung des Ergebnis d12

Die Skalierung geschieht durch Multiplikation mit einer beliebigen Zahl, diegroßer als 1.0 ist.

7. if (d < 0.01) then d als Alphakomponente fur das aktuelle Fragment,if (d ≥ 0.01) then d1.45als Alphakomponente

Wurde man diesen Schritt weglassen, so wurde die Transparenz der Wolkelinear zunehmen, durch eine solche if-Verzweigung nimmt sie hingegen ex-ponentiell zu.

12d liegt zwischen 0.0 und 1.0, wie es fur die Alphakomponente ublich ist.

10

Page 12: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

3.3 Beleuchtung

Fugt man der bisherigen Implementation noch eine Beleuchtungsmoglichkeit furdie Wolken hinzu, kann ein noch realistischeres Aussehen erzeugt werden. Um dieBeleuchtung vorzunehmen, wird zunachst die Normale einer impliziten Gleichungbestimmt. Fur die Normale einer impliziten Gleichung gilt:

F(x,y,z)=0n=∇F(x,y,z)

Um dies im Programm umzusetzen, werden, nachdem die Rauschfunktionerzeugt und in die Rauschtextur gespeichert wurde, die Gradienten der Rausch-funktion bestimmt und in die RGB-Komponenten der Textur geschrieben. Um denNormalenvektor der Wolke zu bestimmen, mussen dann nur noch Gradienten akku-muliert werden. Der dadurch bestimmte Normalenvektor wird im Shader norma-lisiert. Dann wird die Beleuchtung jedes Pixels vorgenommen. Die Ergebnisfarbemit Beleuchtung ergibt sich aus

1-dot(2*(normal.xyz-0.5),position.xyz)

In der Variablen normal ist der Normalenvektor der Wolke und in positiondie Position der Lichtquelle gespeichert.

4 Wasser-Shader

Der in diesem Abschnitt vorgestellte Shader bietet eine Moglichkeit zur Simulationvon Wasser, die zwei entscheidende Faktoren vereint: Sie ist echtzeitfahig und dasErgebnis sieht realistisch aus. Waren diese beiden Faktoren lange Gegensatze, -um einen der beiden Faktoren zu verbessern, musste haufig eine Verschlechterungdes anderen in Kauf genommen werden - ermoglicht es die GPU-Programmierungdiese Gegensatze in einer Applikation zu vereinen. Eine Moglichkeit diese Verei-nigung vorzunehmen, wird hier vorgestellt in Form eines Systems zur Darstellungeiner nahezu unbegrenzten Waseroberflache mit einer kontinuierlichen Wellenani-mation. Beschrieben und erarbeitet wurde dieser Shader von Yung-Feng Chi.13

Das System zur Simulation von Wasser wird in vier Stufen unterteilt:1. Wellengenerierung2. Zerlegung der Oberflache3. Optische Simulation4. Rendern des WasseroberflacheNahezu die gesamte Arbeit wird in Shadern vorgenommen, nur auf der ersten

Stufe werden Berechnungen außerhalb der Shader vorgenommen.Ein solcher Shader kann als Ergebnis beispielsweise eine Darstellung, wie Ab-

bildung 3 sie zeigt, erzeugen.13Yung-Feng Chi: True-To-Life Real-Time Animation of Shallow Water on Today s GPUs. In:

[Eng06], S.467-480

11

Page 13: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

Figure 3: Mit dem in Abschnitt 4 vorgestellten Wasser-Shader erzeugte Darstellung

4.1 Wellengenerierung

4.1.1 Hohenfeld

Zunachst muss eine Form der Wasseroberflachenreprasentation gefunden werden.In diesem Beispiel geschieht dies durch ein Hohenfeld. Dieses Hohenfeld entsprichtim Prinzip einem Gitter, dass auf die Wasseroberflache gelegt wird. In diesemGitter wird an jedem Gitterpunkt die Hohe des Wassers gespeichert. Ein solchesHohenfeld verbraucht nur wenig Speicher und lasst sich leicht rendern. Allerdingswird das Wellenmodell durch diese Form der Reprasentation auf konvexe Formenbeschrankt, was vor allen Dingen das Darstellen brechender Wellen verhindert.Um brechende Wellen dennoch als Teil der Simulation bieten zu konnen, wirdeine zusatzliche Modellierung dieser Wellen, die im Abschnitt 4.3.3 beschriebenist, vorgenommen. Trifft das Wasser die Kuste, wird eine mit Texturen arbeitendeMethode angewendet, um Gischt zu integrieren.

4.1.2 Displacement Mapping

Das Hohenfeld, das zur Darstellung der Wellen verwendet wird, wird mittels Dis-placement Mapping erzeugt. Hierbei handelt es sich um eine Methode einemeinfachen, leicht zu verarbeitenden Modell wie in Abbildung 4 dargestellt ge-ometrische Komplexitat hinzuzufugen und so ein hochaufgelostes Modell zu erhal-

12

Page 14: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

Figure 4: Prinzip des Displacement Mappings

ten.14 Dies geschieht, indem ein Punkt auf der Oberflache genommen und entlangseiner Normalen zu einer neuen Position verschoben wird. Wie stark diese Ver-schiebung ausfallt, hangt von dem in der Displacement Map, bei der es sich um eine2D-Textur handelt, an der entsprechenden Stelle gespeicherten benutzerdefiniertenSkalar ab. Anders als beim Bump Mapping wird bei diesem Verfahren nicht nurdie Oberflachennormale verandert, sondern die Geometrie selbst. Auf diese Artund Weise entsteht das gewunschte Hohenfeld.

4.1.3 Generierung des Hohenfelds

Die Generierung der Wellen ermoglicht die Darstellung von sich bewegendem,die Form veranderndem und mit der Umgebung interagierendem Wasser. Um diegewunschten Wellen und ihre Bewegung zu erzeugen wird auf einen spektralenAnsatz zuruckgegriffen, der es ermoglicht ein eine große Flache umfassendes Hohen-feld zu erstellen. Dieses Hohenfeld ist raumlich und zeitlich unterteilt und enthaltden Hohenwert des Punkts mit der entsprechenden Position zu einem Zeitpunktuber der Horizontalebene. Gespeichert werden kann das Hohenfeld in eine Textur.

Zur Generierung der Hohenkarte werden folgende Formeln verwendet:

H (x, t) =∑h(k, t)eikx

h (k, t) = h0(k)eiω(k)t + h∗0(−k)e−iω(k)t

h∗(k, t) = h(−k, t)

H (x, t)ist das Hohenfeld fur die horizontale Position x eines Punkts, dessenHohe zu einem Zeitpunkt t ausgewertet wird. k ist der Wellenvektor, der in dieRichtung weist, in die sich die Welle bewegt. h0(k)und h∗0(k) entsprechen einemAufruf der entsprechenden Funktionen mit dem Parameter k und t = 0. h (k, t)bestimmt die Amplituden einer Fourierwelle zum Zeitpunkt t.

14vgl. Michael Bunnell: Adaptive Tessellation of Subdivision Surfaces with Displacement Map-ping. In: [Pha05], S. 119

13

Page 15: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

Figure 5: Projektion eines gleichmaßigen Gitters auf die Wasseroberflache zur Zerlegungdieser

Ist die Generierung der Hohenkarte abgeschlossen, wird diese uber die na-hezu unbegrenzte Wasseroberflache aufgespannt. Um unterschiedliche raumlicheAuflosungen der Wellen zu erhalten, wird eine Menge an Hohenkarten mit unter-schiedlicher Skalierung erstellt.15

4.2 Zerlegung der Oberflache

Um die Punkte zu bestimmen, an denen das der Reprasentation der Wasserober-flache dienende Hohenfeld abgetastet werden soll, wird, um eine interaktive Mee-resanimation zu ermoglichen, ein effizientes Zerlegungsschema benotigt. Das Ver-wenden eines vordefinierten Gitters bietet wegen seiner statischen Auflosung keineAlternative zu einem abhangig von der Lage des Augpunkts berechneten. Diegrundlegende Idee, wie eine solche Zerlegung der Wasseroberflache vorgenommenwerden kann, ist ein gleichmaßiges Gitter auf die Wasseroberflache zu projizieren,wie es Abbildung 5 zeigt.16 Die Lage dieses gleichmaßigen Gitters im Verhaltniszur Wasseroberflache ist dabei abhangig von der Blickpyramide. So geschieht es,dass Bereiche der Wasseroberflache, die naher beim Betrachter liegen, feiner un-terteilt sind, als Bereiche, die weiter weg liegen. Auf diese Art und Weise wirdeine Level-of-detail-Funktion gewissermaßen mitgeliefert.

Konkret wird diese Idee wie im Folgenden beschrieben umgesetzt.15vgl. Yung-Feng Chi: True-To-Life Real-Time Animation of Shallow Water on Today’s GPUs.

In: [Eng06], S.47116vgl. Yung-Feng Chi: True-To-Life Real-Time Animation of Shallow Water on Today’s GPUs.

In: [Eng06], S.468

14

Page 16: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

Figure 6: Bestimmen der sichtbaren Region

Findet die Zerlegung wie hier abhangig von der Position des Betrachters statt,genugt eine Zerlegung der sichtbaren Region. Diese sichtbare Region entsprichteinem rechteckigen Ausschnitt der Wasseroberflache, der auch noch die großtenvorkommenden Amplituden der Wellen beinhaltet. Dieser rechteckige Ausschnittwird auf Grundlage der Blickpyramide bestimmt, wie in Abbildung 6 zu sehen ist.Die vier Eckpunkte der sichtbaren Region werden dem Vertex-Shader ubergebenund liegen diesem somit vor.

Die im Bildschirmbereich liegenden Gitterpunkte werden im Fragment-Shaderin den Objektraum projiziert. Dies geschieht mittels einer Division durch die w-Komponente. Die sich daraus ergebenden Gitterpunkte definieren die Positionen,an denen das Hohenfeld ausgewertet wird.

Ein Problem, das noch umgegangen werden muss, tritt auf, wenn der Betrach-ter sich unter der Wasseroberflache befindet und nach oben aus dem Wasser hi-naussieht. In diesem Fall kann es geschehen, dass Bereiche, die eigentlich hinterdem Betrachter liegen, in die sichtbare Region einbezogen werden. Da dies nichtgewunscht ist, verwendet man eine Hilfsbetrachterposition. Die Position des Be-trachters wird hierzu senkrecht zur Horizontalebene nach oben verschoben, bis siesich uber der Wasseroberflache befindet. Diese Hilfsposition wird dann fur dieZerlegung der Wasseroberflache verwendet.

Ist die Projektion im Fragment-Shader vollendet, werden die Hohenfelder un-terschiedlicher Skalierung eines bestimmten Zeitpunkts entlang der horizontalenPosition trilinear abgetastet. Dadurch wird die Displacement Map erstellt.

4.3 Optische Simulation

Das Spiel des Lichts auf der Wasseroberflache ist außerst komplex, muss aber zumErreichen einer realistischen Darstellung angemessen umgesetzt werden. Hierzu

15

Page 17: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

muss ein Beleuchtungsmodell fur die Wasseroberflache entworfen werden. Kanndas Wellenmodell noch pro Eckpunkt und somit im Vertex-Shader ausgewertetwerden, sind die zur optischen Simulation notigen Berechnungen komplexer underfordern deswegen eine Auswertung fur jedes Pixel. Die optische Simulationfindet also im Fragment-Shader statt.

Die Beleuchtung wird in eine Reflexions- und eine Refraktionskomponentezerlegt, die durch eine Fresnelfunktion17 gewichtet werden.

Der sich ergebende Farbwert der Wasseroberflache kann damit wie folgt bes-timmt werden:

Cresult = F (θ) · Creflect + (1− F (θ)) · Crefract

Die Reflexionskomponente Creflect entspricht der Farbe, die aus der uber demWasser liegenden Umgebung entlang des Reflexionsvektors entsteht, wahrend dieRefraktionsfarbe Crefract aus den sich unter Wasser befindenden Objekten resul-tiert. Der Winkel θ ist der Winkel zwischen Betrachter und Wasseroberflache undwird der Fresnelfunktion ubergeben.

Auf dieser Stufe geschehen folgende Vorgange:

• Generieren der lokalen Reflexions- und Refraktionskarte,

• Berechnung von Gischt und Schaum, falls eine ausreichend starke Welle mitder Kuste kollidiert und

• Hinzumischen von Schaum und Gischt fur die entsprechenden Pixel derWasseroberflache in die Refraktionskarte.

4.3.1 Reflexion

Die Reflexionsfarbe selbst kann in drei Komponenten zerlegt werden:1. die Reflexion des Himmels,2. die Reflexion des Sonnenlichts und3. lokale Reflexionen z.B. ein Boot, das auf dem Wasser treibt.

Reflexion des Himmels

Basierend auf Preethams spektralem Strahlungsmodell kann die Reflexion des Lichtsdes Himmels auf der Wasseroberflache bestimmt werden. Dieses Modell benotigtals Eingabewerte die Position der Sonne und die Blickrichtung in die Himmelskup-pel.18

17Geht Licht von einer Materie in eine andere uber, wird immer Licht reflektiert. Der durch dieFresnelfunktion bestimmte Reflexionskoeffizient, der dieses Phanomen beschreibt, basiert auf demBrechungsindex beider Materialien und dem Einfallswinkel.

18vgl. Yung-Feng Chi: Tru-to-Life Animation Of Shallow Water on Today’s GPUs. In: [Eng06],S.472

16

Page 18: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

Anstatt eine Reflexion des Blickvektors a vorzunehmen, bei der betrachtetwird, wohin der Blickvektor reflektiert wird und was dort zu sehen ist, verwendetman dieses Verfahren fur die Wasseroberflachennormale und die Sonnenposition,hieraus ergibt sich die Farbe des Himmels Cskycolor, die reflektiert wird. Diesewird im Vertex-Shader berechnet.

Zusatzlich wird eine Environment Map verwendet,19 in der die Dichte derWolken im Alphakanal gespeichert ist. Basierend auf dem sich aus dem Blick-vektor ergebenden Reflektionsvektor kann ein Texture-look-up stattfinden:

Ccloud = texEnv(Tcloudmap, Vreflect)

Hieraus ergibt sich folgende Berechnung fur die Reflexion des Himmels:

Cskylight = Cskycolor(1− Ccloud.a) + Ccloud.rgb · Ccloud.a

Reflexion des Sonnenlichts

Um die Reflexion des Sonnenlichts zu bestimmen, wird ein typisches Phongbe-leuchtungsmodell pro Pixel mit großem spekularen Exponent verwendet. Außer-dem wird der Tiefenwert mit einem Glanzterm multipliziert, um so die Form desSonnenlichts auf der Wasseroberflache zu kalibrieren.

Lokale Reflexionen

Die Reflexionsfarbe, die durch die lokale Umgebung verursacht wird, kann be-stimmt werden, indem die Wasseroberflache als Spiegel betrachtet wird. AlleObjekte, die sich uber der Wasseroberflache befinden, werden in eine Reflexions-karte gerendert. Um einen solchen Spiegel zu implementieren, wird die Kamera ander Wasseroberflache gespiegelt und die Szene aus Sicht der gespiegelten Kameragerendert.

Um die Entstehung von Artefakten zu vermeiden, muss an der Wasseroberflacheabhangig von der Wellenhohe und nicht an einer horizontalen Ebene geclippt wer-den. Dadurch werden Pixel ausgelassen, die sich tatsachlich unter Wasser befinden.

4.3.2 Refraktion

Zur Erstellung der Refraktionskarte sind ahnliche Vorgange notig wie zur Erstel-lung der Reflexionskarte. In diese Refraktionskarte werden alle Objekte, die sichunter der Wasseroberflache befinden, gerendert. Da die Refraktion alle Objekte

19Environment Mapping simuliert Objekte, die ihre Umgebung reflektieren, indem eine Umge-bungskarte erstellt wird, in der fur jede Richtung, das einfallende Licht gespeichert wird.

17

Page 19: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

unter Wasser verzerrt, werden alle Objekte gemaß Snells Gesetz20 um 1/1.33 ent-lang der y-Achse skaliert.21

Die Refraktionsfarbe wird approximiert durch:

Crefract =(e−attenuation·distance

)· Cobject +

(1− e−attenuation·distance

Cwater

Die Refraktionsfarbe wird folglich aus der getrubten Objektfarbe und der Farbedes Wassers berechnet. Die Parameter attenuation und distance dienen der Gewich-tung der Objekt- und Wasserfarbe. distance beschreibt die Distanz von der Wasser-oberflache zum Objekt. Bei attenuation handelt es sich um den Schwachungskoef-fizient von Wasser. Fur die Wasserfarbe gilt namlich, dass mit wachsender Distanz,die das Licht bis zum Objekt durch das Wasser zurucklegen muss, die Wahrschein-lichkeit steigt, dass das Licht von Wassermolekulen oder Partikeln verstreut oderabsorbiert wird. Aufgrund dieser Tatsache erscheint zum Beispiel auch flachesWasser transparenter als tiefes. Um solche Dinge zu beachten wird auch die em-pirisch ermitteltete Gewichtung mit Hilfe der e-Funktion vorgenommen.

Zusatzlich enthalt die Wasserfarbe auch Gischeffekte, die nach einer Ausein-andersetzung mit brechenden Wellen im Abschnitt 4.3.3. mit einbezogen werdenkonnen. Die Wasserfarbe berechnet sich aus der mit einem Alphawert Cfoam.a,der in der Gischtextur hinterlegt ist, gewichteten eigentlichen Farbe des WassersCwater und der Farbe der Gischt Cfoam.rgb:

Cwater = Cwater · Cfoam.a+ Cfoam.rgb(1− Cfoam.a)

4.3.3 Brechende Wellen

Fur die Gischeffekte gilt, dass Schaum immer auf der Wasseroberflache liegt. Deswe-gen wird zum Rendern des Schaums eine Methode, die mit einer animierten Schaum-textur arbeitet, verwendet. Der Inhalt dieser animierten Textur wird mit der Wasser-oberflache vermischt. Damit dies stattfinden kann, muss fur jedes Pixel die Mengedes Schaums sowie ein Blending-Faktor α der Wasseroberflache berechnet werden.

Aus der Hohe des Terrains und der Hohe der Welle ergibt sich, ob eine brechen-de Welle vorliegt. Mit Hilfe der Differenz zwischen der Hohe der Welle Hw undder Hohe des Terrains Ht wird anhand eines Schwellwerts festgelegt, ob Gischtzur Wasseroberflachenfarbe hinzu gemengt werden muss. Eine Vorstellung hier-von vermittelt Abbildung 7, in der im grau hinterlegten Bereich Gischt entsteht.Der Grenze, ab wann Gischt existiert, wird empirisch gewahlt, um eine moglichstrealistische, naturgetreue Darstellung zu gewahrleisten.

20Das auch als snelluissches Brechungsgesetz bezeichnete Gesetz besagt, dass eine Welle (z.B. einLichtstrahl) ihre Richtung andert, also gebrochen wird, wenn sie von einem transparenten Medium inein anderes transparentes Medium mit einer anderen Phasengeschwindigkeit ubergeht. Es besagt nur,in welche Richtung die Welle abgelenkt wird, nicht aber, wie viel von der Welle an dem Ubergangzwischen den beiden Medien transmitiert beziehungsweise reflektiert wird.

21vgl. Yung-Feng Chi: True-To-Life Animation of Shallow Water on Today’s GPUs. In: [Eng06],S.474

18

Page 20: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

Figure 7: Anhand der Hohe des Terrains und der Hohe der Welle bestimmter Bereich, indem Gischt entsteht

4.4 Rendern der Wasseroberflache

Zuletzt wird die Wasseroberflache gerendert. Nun wird die Displacement Map furdie Wellenanimation und die Farbberechnung angewendet, indem mit den in ihregespeicherten Werten die Position entlang der Normale verschoben wird.

Um die Reflexion des Sonnenlichts in die Reflexionsfarbe mit einbeziehen zukonnen, erhalt der Fragment-Shader die Richtung des Sonnenlichts als Eingabe.Im Fragment-Shader findet ein Look-up der Reflexions- und Refraktionskarte statt,wodurch die finale Farbe fur jedes Fragment der Wasseroberflache bestimmt wer-den kann.

5 Einleitung des praktischen Teils

Der restliche Teil dieser Ausarbeitung beschaftigt sich mit einem Programmbeispiel,das zwei Shadersysteme benutzt.Zuerst wird eine Klasse vorgestellt, die den Umgang mit Shadern erleichtert unddarauf aufbauend werden die beiden Shadersysteme anhand von Quellcode detail-liert beschrieben.

6 Formatierungen

Um Variablen, Gleichungen, Funktionen und Quellcode visuell voneinander abzu-grenzen werden folgende Schreibweisen benutzt:

• Dick ohne Serifen wird fur Funktionen benutzt.

• Kursiv ohne Serifen wird fur Variablen-, Parameter- und Klassennamenbenutzt.

• Kursiv mit Serifen wird fur Gleichungen benutzt.

19

Page 21: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

• Fur den Quellcode wird eine umrahmte Monospace-Schriftart verwendet.

7 Voraussetzungen fur dieses Projekt

7.1 Bibliotheken

Es werden außer der schon bekannten GLUT Bibliothek noch die ”OpenGL Exten-sion Wrangler Library“ 22 und die ”GLUI User Interface Library“ 23 gebraucht.Die GLEW Bibliothek ist n”otig, um die fur die Shaderprogrammierung notigenFunktionen verfugbar zu machen und zu uberprufen, ob die Grafikkarte OpenGL2.0 unterstutzt. OpenGL 2.0 wird benotigt, weil es die erste Version von OpenGList, die Shaderprogramme ohne die Benutzung von Extensions zur Verfugung stellt.Ist GLEW eingebunden, lasst sich mit wenigen Zeilen Code die OpenGL Versionuberprufen:

glewInit();if (glewIsSupported("GL_VERSION_2_0")){printf("Ready for OpenGL 2.0\n");

}else{printf("OpenGL 2.0 not supported\n");exit(1);

}

8 Die Klasse ShaderContainer

8.1 Beschreibung

Um die Verwaltung der Shader zu vereinfachen, habe ich die Klasse Shader-Container geschrieben. Sie ist die Schnittstelle zwischen der normalen OpenGL-Anwendung und den Shaderprogrammen. Sie ubernimmt das Laden, Kompilieren,Binden, Linken und Aktivieren der Shader und ermoglicht es Applikationsdaten anSampler-, Attribut- und Uniformvariablen im Shader zu binden.

8.2 Benutzung der Klasse ShaderContainer

Zuerst muss wie schon gesagt uberpruft werden, ob die Grafikkarte und der ver-wendete Treiber, OpenGL 2.0 unterstutzt. Ist die Unterstutzung gewahrleistet,

22http://glew.sourceforge.net/23http://glui.sourceforge.net/

20

Page 22: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

kann ein ShaderContainer - Objekt angelegt werden. Die Funktion setShadersubernimmt das Laden, Kompilieren, Binden und Linken des Vertex- und Frag-mentshaders.Falls der Shader Texturen benotigt, muss der Shader aktiviert werden, eine Tex-tureinheit aktiviert werden und die gewunschte Textur gebunden werden. Nun kannuber die Funktion setSampler die Textureinheit an den Samplervariablennamenim Shader gebunden werden. Der folgende Quellcode zeigt das Beschriebene:

void initializeShader(){ShaderContainer::openGL20Support();ShaderContainer *shader = new ShaderContainer();shader->setShaders("ShaderSource.vert","ShaderSource.frag");// Falls der Shader Texturen benoetigt, muessen sie// nun an die Samplervariablen gebunden werden.if(shaderBenoetigtTexturen){shader->enableShaders();// Bilddaten in eine Textur laden.// TexturUnit aktivieren und Textur binden.shader->setSampler(char * uniformSamplername,GLuint texturUnit);

shader->disableShaders();}

}

In der Zeichenroutine mussen die Funktionen enableShaders und disableShaders,die durch den Shader zu zeichnenden Primitive umschließen. Falls der Shader Ap-plikationsdaten fur Uniforme- oder Attributvariablen braucht, mussen diese Daten,nach der Aktivierung des Shaders, an die entsprechenden Variablennamen im Shadergebunden werden. Die spater folgenden Beispiel fur das Partikelsystem und dasReflexions-Refraktionssystem gehen auf das ”Hochladen“ von Applikationsdatenin einen Shader genauer ein.Im Folgenden wird ein ein Teopot mit einem Shader gezeichnet:

void display(){...shader->enableShaders();// Falls der Shader Attribut- oder Uniformvariablen// benoetigt, koennen diese jetzt aktualisiert werdenglutSolidTeapot(1.0);shader->disableShaders();

}

21

Page 23: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

Wenn das Programm beendet wird, sollte der Speicher wieder frei gegeben werden:

cleanUp(){delete shader;

}

8.3 Aufgabe der Funktion setShaders

Sie ist die Kernfunktion der Klasse ShaderContainer (der Quellcode der set-Shaders-Funktion stammt großtenteils von http://www.lighthouse3d.com/opengl/glsl/index.php?oglexample1):

setShaders(char * vsFilename, char * fsFilename)

Sie erstellt zuerst zwei leere Shaderobjekte und ein leeres Programmobjekt, derenHandles sie in Membervariablen ablegt:

program = glCreateProgram();vertexShader = glCreateShader(GL_VERTEX_SHADER);fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);

Jetzt kann der Quellcode der Shader, aus zwei Textdateien eingelesen werden unduber die Handles der Shaderobjekte in die Objekte geladen werden:

vs = textFileRead(vsFilename);fs = textFileRead(fsFilename);glShaderSource(vertexShader, 1, &vv,NULL);glShaderSource(fragmentShader, 1, &ff,NULL);

Danach wird der Quellcode in den Shaderobjekten kompiliert, die beiden Objektean das Programmobjekt gebunden und das Programmobjekt gelinkt:

glCompileShader(vertexShader);glCompileShader(fragmentShader);

glAttachShader(program,vertexShader);glAttachShader(program,fragmentShader);

glLinkProgram(program);

Das Linken kann aus folgenden Grunden fehlschlagen:

• Die Anzahl der von der Implementation zur Verfugung gestelltenAttributvariablen wurde uberschritten.

• Die Anzahl der von der Implementation zur Verfugung gestelltenUniformvariablen wurde uberschritten.

22

Page 24: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

• Der Speicherplatz fur Uniformvariablen wurde uberschritten.

• Die Anzahl der von der Implementation angebotenen Samplerwurde uberschritten.

• Der Haupt-Funktionskorper(main) fehlt bei Vertex- oder Frag-mentshader.

• Die Liste der im Vertexshader festgelegten Varying-Variablenunterscheidet sich von der im Fragmentshader.

• Referenzen auf nicht-definierte Funktionen oder Variablen.

• Eine verteilte globale Variable (shared global) wurde mit unter-schiedlichen Typen oder Vorgabewerten deklariert.

• Einer oder mehrere der angehangte(n) Shader wurde nicht erfol-greich kompiliert.

• Es wurden nicht genug aufeinanderfolgende Vertex-Attribut-Slotsgefunden um Attributmatrizen zu binden.

• Das binden einer generischen Attribut Matrix fuhrt dazu, dasseinige Zeilen der Matrix das Maximum uberschreiten.24

Um eine Fehlerausgabe zu erhalten sollte nach dem Linken glGetShaderInfoLogfur die Shaderobjekte, und glGetProgramInfoLog fur das Programmobjekt aufgerufenwerden. Da die Aufrufe der beiden Funktionen nicht nur die Handles der Objekteals Parameter brauchen, gibt es in der Klasse ShaderContainer zwei Wrapper-funktionen, die die Parameter ermitteln und daraufhin glGetShaderInfoLog undglGetProgramInfoLog aufrufen:

printProgramInfoLog(program);printShaderInfoLog(vertexShader, VERTEX_SHADER);printShaderInfoLog(fragmentShader, FRAGMENT_SHADER);

Nach erfolgreichen Linken, kann der Shader, wenn er aktiviert wird, zum Rendernbenutzt werden.

9 Grober Aufbau des Projekts

Das Projekt besteht aus einem normalen Glut-Programm, das zusatzlich Glui-Steuerelementeverwendet, um mit den Shadern zu interagieren. Uber die eben vorgestellte KlasseShaderContainer wird fur jeden Shader eine Instanz erzeugt. Durch die Funk-tionen enableShaders() und disableShaders() werden die Shader in den Ze-ichenfunktionen ein- und ausgeschaltet.

24vgl. http://wiki.delphigl.com/index.php/glLinkProgram

23

Page 25: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

10 Die verwendeten Shader

Figure 8: Partikel- und Reflexions/Refraktionsshader

Die Grafik in Abbildung 8 zeigt die beiden Shader, die die Anwendung benutzt.Der Reflextions-Refraktionsshader zeichnet die Kanone, in der sich die dynamis-che und statische Umgebung der Szene spiegelt. Der Partikelshader zeichnet dasKonfetti, das die Kanone verschießt. Der Rest der Szene wird mit der normalenOpenGL- Pipeline gezeichnet.

11 Der Partikelshader

Das erste Partikelsystem, das uber eine Reihe von Initialzustanden und Wahrschein-lichkeitsregeln modelliert wurde, wurde von Bill Reeves und Lucasfilms entwick-elt. Im Film ”Star Trek II: Der Zorn des Khan“ wurde es benutzt um eine Feuer-szene zu rendern. Diese Szene ist auch als ”The Genesis Demo“ bekannt.Partikelsysteme werden benutzt um verschwommene, nicht greifbare Objekte (imEnglischen ”fuzzy“- things) darstellen und rendern zu konnen. Darunter fallen zumBeispiel Naturphanomene wie Rauch, Feuer, Spruhnebel und Ahnliches.25

Das nun vorgestellte Partikelsystem basiert in seiner Grundstruktur auf dem Beispieldes OpenGL Shading Language Buchs [Ros06] in Kapitel 16.7.

25vgl.[Ros06], S.418

24

Page 26: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

11.1 Ziele des Partikelshaders

Um eine moglichst Echtzeitfahige Darstellung der Partikel zu gewahrleisten solltenfolgende Zielvorgaben gesetzt werden:

• Moglichst alle Berechnungen der Partikel sollten auf der GPU stattfinden. 26

• Es sollte keinen merkbaren Performanzeinbruch beim Einsatz des Shadersgeben.

• Folgende Voraussetzungen gelten deshalb fur die Partikel:

– Keine Kollision mit anderen Partikeln.

– Sie emittieren Licht.

– Sie werfen keinen Schatten auf andere Partikel.27

11.2 Partikelverhalten

Figure 9: Konfettiverhalten

Das Ziel ist eine sich anfangs schnell ausbreitende Konfettiwolke, die spaterlangsam zu Boden sinkt (siehe Abbildung 9). Dabei sollen nahe Konfettipartikelgroßer sein als weiter entfernte. Fur den einzelnen Partikel heißt das, dass er zuBeginn der Animation stark, und spater nur noch wenig bis gar nicht beschleunigtwird.

11.2.1 Suche nach einer Weg- Zeitfunktion

Eine geeignete Funktion um den zuruckgelegten Weg in Abhangigkeit von der Zeitmit dem gewunschten Verhalten zu beschreiben, ware z.B. eine Parabel die an derersten Winkelhalbierenden gespiegelt ist (siehe Abbildung 10). Allerdings ist dieanfangliche Steigung der gespiegelten Parabel zu gering, um eine große Beschleu-nigung, wie sie bei einem Schuss der Fall ist, zu simulieren. Um also am Anfang

26vgl. [Ros06], S.41927vgl. [Ros06], S.419

25

Page 27: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

Figure 10: Parabel und gespiegelteParabel

Figure 11: vierte Wurzel undzweite Wurzel

der Animation eine noch starkere Beschleunigung zu erreichen, eignet sich daherdie Funktion:

s(t) = 4√t (siehe Abbildung 11) (1)

Damit man in Beschleunigung und Startort der einzelnen Partikel variieren kann,wird die Funktion um den Faktor Energie und den Summand Startposition er-weitert:

s(t) = StartPosition+ Energie ∗ 4√t (2)

Durch die beiden neuen Parameter ist es moglich jedem Partikel eine andere Flug-bahn zu geben. Die Erdanziehung und den Luftwiderstand simuliert eine weitereWegzeitfunktion:

s2(t) = 0.9 ∗ t2 (3)

Der durch diese Funktion errechnete Weg wird nur von der Y-Komponente sub-trahiert. So ergeben sich fur jeden Partikel folgende endgultige Formeln:

sxz(t) = StartPosition+ Energie ∗ 4√t (siehe Abbildung 12)

sy(t) = StartPosition+ Energie ∗ 4√t− 0.9 ∗ t2 (siehe Abbildung 13)

(4)

26

Page 28: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

Figure 12: Wegzeitfunktion derX- und Z-Komponentemit verschiedenenEnergien

Figure 13: Wegzeitfunktion der Y-Komponente mit ver-schiedenen Energien

11.3 Benotigte Daten pro Partikel

Außer der Startposition und Energie benotigt jeder Partikel noch eine Startzeit, sieermoglicht es erst die Position zu einer bestimmten Lebenszeit t (t = globaleZeit−Startzeit) zu bestimmen und verhindert, dass alle Partikel zur gleichen Zeit starten.Die globale Zeit wird fur jedes gezeichnete Bild von der Applikation erhoht. ZumSchluss bekommt jeder Partikel noch eine Farbe. Somit fallen folgende Daten an:

• Pro Partikel:

– 3D Vektor fur die Startposition (XYZ).

– 3D Vektor fur die Schussenergie (XYZ).

– 3D Vektor fur die Farbe (RGB).

– Eine Fließkommazahl fur die Startzeit.

– Die Große des Partikels lasst sich aus dessen Position bestimmen: Sieverhalt sich antiproportional zu dem Abstand zwischen Partikel undKamera.

• Pro Frame

– Ein globaler Zeitwert fur alle Partikel

27

Page 29: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

11.4 Schematischer Aufbau des Partikelsystems

Figure 14: Zusammenhang zwischen Applikation und Shader

Wie man in Abbildung 14 sieht werden fur Partikelfarbe und Position einge-baute Attribute (built-in attributes) verwendet, fur die Energie und Startzeit jedochbenutzerdefinierte Attribute. Diese Unterscheidung ist wichtig, da sich das Bindender Applikationsdaten an die Shaderattributvariablen ein wenig unterscheidet. Desweiteren erkennt man, dass die Applikation sich nur um die Erstellung der initialenZustande der Partikel kummern muss. Den Rest der Berechnungen ubernehmendie Shader. Der Vertexshader berechnet die Lebenszeit t, die Große und die Posi-tion der Partikel. Der Fragmentshader entscheidet nur welche Partikel gezeichnetwerden.

11.5 Erstellung der Attributdaten

Der folgende Codeausschnitt zeigt die Erstellung der Initialdaten der Partikel, diespater in die Shader ”hochgeladen“ werden:

for(x = 0.5 / w - 0.5; x < 0.5; x = x + 1.0 / w)for(z = 0.5 / h - 0.5; z < 0.5; z = z + 1.0 / h){//Vertex position calculationvptr[index] = x;vptr[index + 1] = 0; //yvptr[index + 2] = z;

//Vertex color calculation//Rcptr[index] = ((float)rand()/RAND_MAX)*0.5+0.5;

28

Page 30: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

//Gcptr[index + 1] = ((float)rand()/RAND_MAX)*0.5+0.5;//Bcptr[index + 2] = ((float)rand()/RAND_MAX)*0.5+0.5;

//ShotPower calculation//Shot energy Xpwrptr[index] = ((float)rand()/RAND_MAX)*6-3.0;//Shot energy Ypwrptr[(index + 1)] = ((float)rand()/RAND_MAX)*6+5.0;//Shot energy Zpwrptr[index + 2] = ((float)rand()/RAND_MAX)*6+1.5;

index = index + 3;

//start time calculationstptr [timeIndex] = ((float)rand()/RAND_MAX) * 0.1;timeIndex++;}

28

Die Beiden for-Schleifen haben die Startposition in der XZ-Umgebung von -0.5bis +0.5 erzeugt, Farben im RGB-Bereich von 0.5 bis 1.0 und Startzeiten im Inter-vall von 0.0 bis 0.1. Die Schussenergien liegen fur die X-Komponente im Bereichvon -3.0 bis +3.0, fur die Y-Komponente im Bereich von 5.0 bis 11.0 und fur dieZ-Komponente im Bereich von 1.5 bis 7.5. Die Bedeutung der Werte der Schussen-ergien wird klar, wenn man sich uberlegt, dass die Kanone im Ursprung steht undentlang der Z-Achse schießt. So muss in X-Richtung, damit die Kanone geradeausschießt, eine gleichmaßige Streuung der Energien (-3.0 bis +3.0) herrschen. DieZ-Komponente beschreibt demnach das Beschleunigungsverhalten in Schussrich-tung (deshalb ist dieser Bereich mit den hochsten Werten belegt) und als letztesbeschreibt die Y-Komponente das Flugverhalten in die Hohe.

11.6 ”Hochladen” der erstellten Daten in den Shader

Im folgenden Abschnitt wird beschrieben, wie die von der Applikation erstelltenDaten in die Shader geladen werden.

11.6.1 ”Hochladen“ der globalen Zeit

Quellcode um die globale Zeit fur jedes Bild im Shader zu aktualisieren:

GLint loc;// "time" ist der Name der uniformen Variable im Shader

28vgl. [Ros06], S.421

29

Page 31: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

loc = glGetUniformLocation(program,"time");if(loc == -1)fprintf(stderr,"No such uniform named \"%s\"\n","time");

glUniform1f(loc, particleTime);

Alternativ kann das ”Hochladen “ auch unter der Benutzung der Klasse Shader-Container stattfinden:

shaderContainer->setUniform1f("time", particleTime);// Nach jedem "Hochladen" muss die Zeit erhoeht werdenparticleTime += 0.03f;

11.6.2 ”Hochladen” der built-in Attribute

...//Vertexshader (Beispiel)void main(){...vec4 vert = gl_Vertex;vec4 color = gl_Color;

}

Um Applikationsdaten an die eingebauten Attributvariablen gl Vertex und gl Color ,wie sie der obige Vertexshader zeigt, zu binden, wird folgender Quellcode ge-braucht:

confettiShader->enableShaders();//In ConfettiCannon.cpp drawConfetti()glVertexPointer(3, GL_FLOAT, 0, vptr);glColorPointer(3, GL_FLOAT, 0, cptr);glEnableClientState(GL_VERTEX_ARRAY);glEnableClientState(GL_COLOR_ARRAY);glDrawArrays(GL_POINTS, 0, w * h);glDisableClientState(GL_VERTEX_ARRAY);glDisableClientState(GL_COLOR_ARRAY);confettiShader->disableShaders();

glVertexPointer beschreibt Lage und das Datenformat einer Reihe (Array) vonVertex-Koordinaten die spater zum Rendern benutzt werden sollen. 29

glColorPointer bestimmt den Ort und das Datenformat eines Farbkomponenten-Arrays, das zum Rendern benutzt werden soll. 30)

29http://wiki.delphigl.com/index.php/glVertexPointer30http://wiki.delphigl.com/index.php/glColorPointer

30

Page 32: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

glEnableClientState und glDisableClientState aktiviert oder deaktiviert client-seitig Ressourcen.31

glDrawArrays definiert mehrere geometrische Primitiven mit sehr wenig Unter-funktionsaufrufen.32

11.6.3 ”Hochladen” der benutzerdefinierten Attribute

Das Binden an benutzerdefinierte Attributvariablen unterscheidet sich von demeingebauter Attributvariablen:

//Vertexshader (Beispiel)attribute vec3 shotPower;void main(){... }

Der obige Vertexshader zeigt die benutzerdefinierte Attributvariable shotPower ,die mit den beiden folgenden Codefragmenten an die Applikationsdaten gebundenwerden:

//In ConfettiCannon.cpp. Nur einmaliger Aufruf#define SHOTPOWERARRAY_ARRAY 3...confettiShader->bindAttribLocation(SHOTPOWERARRAY_ARRAY, "shotPower");

//In ConfettiCannon.cpp drawConfetti()glVertexAttribPointer(SHOTPOWERARRAY_ARRAY, 3, GL_FLOAT, GL_FALSE, 0,pwrptr);glEnableVertexAttribArray(SHOTPOWERARRAY_ARRAY);glDrawArrays(GL_POINTS, 0, w * h);glDisableVertexAttribArray(SHOTPOWERARRAY_ARRAY);

Zuerst muss ein Name in Form von einer Zahl an die benutzerdefinierte Attribut-variable gebunden werden (ahnlich wie bei Texturen) und erst danach konnen uberdie Funktion glVertexAttribPointer die wirklichen Daten an die Variable gebun-den werden. Das Starttimearray wird analog hochgeladen.

11.6.4 Die gesamte Zeichenmethode des Konfettipartikelshaders

Der folgende Quellcode zeigt an einem Stuck das ”Hochladen“ aller Attributdatenund den Aufruf zum Zeichnen.

//Built-in Attributvariablen werden "hochgeladen".glVertexPointer(3, GL_FLOAT, 0, vptr);

31http://wiki.delphigl.com/index.php/glEnableClientState32http://wiki.delphigl.com/index.php/glDrawArrays

31

Page 33: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

glColorPointer(3, GL_FLOAT, 0, cptr);/Benutzerdefinierte Attribute werden "hochgeladen".//Die Namen (z.B. SHOTPOWERARRAY) der//benutzerdefinierten Attributarrays//mussen zuvor an die Attributvariable im//Shader gebunden werden: glBindAttribLocation(..);glVertexAttribPointer(SHOTPOWERARRAY_ARRAY,3, GL_FLOAT, GL_FALSE, 0, pwrptr);

glVertexAttribPointer(START_TIME_ARRAY,1, GL_FLOAT, GL_FALSE, 0, stptr);

//Aktiviert die Attributarrays. Alle//Arrays, die aktiviert werden, sollten//zuvor auch definiert sein.glEnableClientState(GL_VERTEX_ARRAY);glEnableClientState(GL_COLOR_ARRAY);glEnableVertexAttribArray(SHOTPOWERARRAY_ARRAY);glEnableVertexAttribArray(START_TIME_ARRAY);

//Der Vertexshader soll spater die//Punktgroße einstellenglEnable(GL_VERTEX_PROGRAM_POINT_SIZE);if(antialiasingFlag)//"Runde" Partikel werden eingeschaltetglEnable(GL_POINT_SMOOTH);

glDrawArrays(GL_POINTS, 0, w * h);

//Widerherstellen des alten OpenGL - Zustandsif(antialiasingFlag)glDisable(GL_POINT_SMOOTH);

glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);

glDisableClientState(GL_VERTEX_ARRAY);glDisableClientState(GL_COLOR_ARRAY);glDisableVertexAttribArray(SHOTPOWERARRAY_ARRAY);glDisableVertexAttribArray(START_TIME_ARRAY);

33

33vgl. [Ros06], S.422

32

Page 34: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

11.7 Der Vertexshader

Der Vertexshader besteht wie schon vorher erwahnt, aus der Berechnung der Leben-szeit t , der Position gl Position , der Große gl Position und aus dem Setzen derFarbe gl Color . Damit der Fragmentshader nur die ”lebenden“ Partikel zeichnet,muss die Lebenszeit an ihn weitergegeben werden. Die Zeit t ist deshalb eine Vary-ingvariable. Hier noch einmal die Wegzeitfunktion um die Postion zu ermitteln:

sxz(t) = StartPosition+ Energie ∗ 4√t

sy(t) = StartPosition+ Energie ∗ 4√t− 0.9 ∗ t2

(5)

Die berechnete Position muss allerdings noch in das Kamerakoordinatensystemtransformiert werden und mit der Projektionsmatrix multipliziert werden:

uniform float time;attribute vec3 shotPower;attribute float startTime;varying vec4 color;varying float t;void main(){vec4 vert;//Berechnung der Lebenszeitt = time - startTime;

//Berechnung nach der Wegzeitfunktionvert = gl_Vertex + vec4(pow(t, 0.25) * shotPower, 0.0);vert.y -= 0.9 * t * t;

//setzen der Farbecolor = gl_Color;

//Abstandsabhangige Groeße://Großer Abstand -> kleine Partikelgroesse//Kleiner Abstand -> grosse Partikelgroessegl_PointSize = -1/(gl_ModelViewMatrix * vert).z * 30.0;

//Transformation und Projektion//der berechneten Positiongl_Position = gl_ModelViewProjectionMatrix * vert;}

34

34vgl. [Ros06], S.424

33

Page 35: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

11.8 Der Fragmentshader

Die Aufgabe des Fragmentshaders besteht alleine darin noch nicht lebende Partikeldurch den Aufruf von discard zu verwerfen.

varying vec4 color;varying float t;

void main (void){if(t < 0.0)

discard; //Partikel wird verworfen

elsegl_FragColor = color;

}

12 Refraktion und Reflexion

Refraktion ist die Ablenkung von Licht, wenn es Materialien mit verschiedenenoptischen Dichten durchdringt. Man sieht diesen Effekt, wenn man Dinge betra-chtet, die sowohl unter- als auch uber der Wasseroberflache liegen. Er beruht aufden verschiedenen Lichtgeschwindigkeiten in Materialien mit unterschiedlichemBrechungsindex. Der Brechungsindex auch Brechzahl genannt, ist das Verhaltnisder Lichtgeschwindigkeiten im Vakuum und des zu untersuchenden Materials.35

nm = c0/cm Das Refraktions-Reflexionssystem aus dem OpenGL Shading Lan-guage Buch ([Ros06]) im Kapitel 14.1 habe ich als Grundlage fur die dynamischeund statische Reflexion-Refraktion benutzt.

12.1 Fresnel-Effekt

Auffallig ist, dass viele refraktierende Materialien bei flachen Einfallswinkeln auchreflektierend sind. So spiegelt sich in einem See, wenn man vor ihm steht dessenUmgebung. Dieser Effekt wird Fresnel Effekt genannt. Die Fresnelgleichungbeschreibt das Verhaltnis zwischen Reflexion und Refraktion aufgrund des Einfall-swinkels, der Polarisation und der Wellenlange des Lichts, sowie den Brechzahlender beiden Materialien 36.Die Grafik in Abbildung 15 zeigt den Fresnel-Effekt: Am Rand der Kugel siehtman einen hohen Reflexionsanteil, da hier der Einfallswinkel sehr flach ist.

35vgl. [Ros06], S.35836vgl. [Ros06], S.359

34

Page 36: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

Figure 15: Fresnel Effekt

12.2 Vereinfachendes Modell

Da die Fresnelgleichungen relativ komplex sind werden fur den Shader verein-fachende Annahmen gemacht:

• Das Licht wird nur am Eintrittspunkt der Oberflache gebrochen.

• Das Licht ist nicht polarisiert.

• Die Approximation der Fresnel Gleichung von Christophe Schlick reichtaus.37

Approximation von Christophe Schlick:

eta =n1

n2

f =(1.0− eta)2

(1.0 + eta)2

(6)

F = f + (1.0− dot(V,N))FresnelPower (7)

37vgl. [Ros06], S.359

35

Page 37: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

Dabei ist V der einfallende Vektor, N die Normale, n1 und n2 die Brechzahlen derbeiden Materialien, FresnelPower ein weiterer Parameter, um den Grad der Re-flexion bei flachen Einfallswinkeln zu steuern und das Ergebnis F gibt das Verhalt-nis zwischen Reflexion und Refraktion an.

36

Page 38: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

12.3 Schematischer Aufbau des Reflexion/Refraktionssystems

Figure 16: Aufbau des Reflexion/Refraktionssystems

Wie man in Abbildung 16 sieht braucht man außer dem Verhaltnis der Brechzahlen(eta) und der Fresnel-Power (FresnelPower ) noch eine Kamera-zu-Welt-Matrix(camToWorld) im Vertexshader. Der Grund fur diese Matrix wird im nachstenAbschnitt erklart. Die Aufgabe des Vertexshaders besteht darin den Reflexions-und Refraktionsvektor (refractVector , reflectVector ), sowie mit der Approxi-mation von Christophe Schlick den Anteil von Refraktion zu Reflexion (ratio)zu berechnen. Aus diesen drei Parametern, die als Varyingvariable an den Frag-mentshader weitergegeben und interpoliert werden, berechnet der Fragmentshaderuber die Cubemaps (dynamicCM , staticCM) die Pixelfarbe.Die Applikation muss sich hierbei nur um das ”Hochladen” der gennannten Datenin die Shader kummern. Dabei ist jedoch zu beachten, dass bei der Spiegelungeiner dynamischen Umgebung, wie es hier der Fall ist, pro Bild eine Cubemaptex-tur aktualisiert werden muss. Dieses ist die dynamische Cubemap, sie beinhaltetalle virtuellen Objekte der Szene, wohingegen die statische Cubemap einen un-endlich weiten Hintergrund speichert.

37

Page 39: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

12.4 Ursache der Kamera-zu-Welt-Matrix

Figure 17: Reflexion und Refraktion

Um zu verstehen weshalb die Kamera-zu-Welt-Matrix benotigt wird muss mansich die entsprechenden Codezeilen im Vertex- bzw. Fragmentshader ansehen:

//Vertexshadervarying vec3 refractVector;varying vec3 reflectVector ;uniform float eta; // z.B. 0.66 (Luft Glas)...refractVector = refract(i, n, eta);reflectVector = reflect(i, n);...

...//Fragment shadervec4 reflectColor = textureCube(cubeMap, reflectVector);vec4 refractColor = textureCube(cubeMap, refractVector);...

38

Page 40: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

Wie man sieht benotigt der Fragmentshader um die Reflexions- und Refraktions-farbe zu ermitteln einen Reflexions- und Refraktionsvektor. Dieser muss in Weltko-ordinaten sein. Die einfachste Losung ware also den Einfallsvektor i im Ver-texshader in Weltkoordinaten zu berechnen(i = KameraPositionWK−PunktPositionWK)und mit den Refraktions- und Reflexionsfunktionen die Vektoren in Weltkoordi-naten zu bestimmen. Allerdings ginge durch diese Losung jegliche Transforma-tion der Eckpunkte verloren, da die Transformationen in der Modelview-Matrixstecken.Um auch die Transformationen zu berucksichtigen, mussen also die Eckpunkteund die Normalen mit der Modelview-Matrix bzw mit der invers-transponiertenModelview-Matrix multipliziert werden, dadurch ist jedoch auch der berechneteReflexions- und Refraktionsvektor in Kamerakoordinaten. Also mussen diese bei-den Vektoren zurucktransformiert werden und zwar mit der Kamera-zu-Welt-Matrix.

12.4.1 Bestimmung der Kamera-zu-Welt-Matrix (fur Vektoren)

Fur Punkte ist es die Inverse der gluLookAt-Matrix. Fur Vektoren muss man vondieser Matrix die transponierte Inverse bilden:

cam2World = (((gluLookAtMatrix)−1)−1)T

cam2World = (gluLookAtMatrix)T(8)

float camToWorld [16];glGetFloatv(GL_MODELVIEW_MATRIX, camToWorld);MATRIX4X4 matrix = MATRIX4X4(camToWorld);matrix.Transpose();shader->setUniformMatrix4fv("camToWorld", 1, false, matrix.entries);

12.5 Erzeugung einer dynamischen Cubemap

Pro Bild und pro reflektierenden Objekt muss in alle sechs Raumrichtungen einBild in die Cubemaptextur gerendert werden (siehe Abbildung 18). Zunachst wirdeine leere Cubemap erzeugt:

glGenTextures(1, ID);glBindTexture( GL_TEXTURE_CUBE_MAP, *ID);glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_S, GL_REPEAT);

glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_T, GL_REPEAT);

glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_R, GL_REPEAT);

glTexParameteri(GL_TEXTURE_CUBE_MAP,

39

Page 41: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

Figure 18: Einstellungen der Kamera um die dynamische Cubemap zu rendern.

GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0,GL_RGBA,width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X,... );

glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y,...);glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,...);

glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z,...);glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,...);

Da der Viewport, die Modelviewmatrix und die Projektionsmatrix geandert werdenmussen, um in die Cubemap zu rendern, mussen sie gesichert werden:

//Viewport sichernGLint viewport[4];glGetIntegerv(GL_VIEWPORT, viewport);GLint oldWidth = viewport[2];GLint oldHeight = viewport[3];

//Projektionsmatrix sichernglMatrixMode(GL_PROJECTION);glPushMatrix();glLoadIdentity();

40

Page 42: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

//90◦ Offnungswinkel um eine//nahtlose Cubemap zu erhaltengluPerspective (90, 1.0f, 0.01, 500);glViewport(0, 0, w, h);

//Modelviewmatrix sichernglMatrixMode(GL_MODELVIEW);glPushMatrix();glLoadIdentity();

Jetzt kann in die Cubemaptextur gerendert werden. Dazu wird mit dem gluLookAt-Befehl die Kamera nacheinander in die sechs Raumrichtungen gesetzt und jeweilseine Funktion aufgerufen, die den so sichtbaren Bereich in die jeweils Teiltextur derCubemap rendert. Am Ende der Prozedur wird der Viewport, die Modelviewmatrixund die Projektionsmatrix wiederhergestellt.

gluLookAt(pos.x, pos.y, pos.z, pos.x + 1.0, pos.y,pos.z, 0.0, -1.0, 0.0);

copyToCubeMapTexture(GL_TEXTURE_CUBE_MAP_POSITIVE_X);

gluLookAt(pos.x, pos.y, pos.z, pos.x - 1.0, pos.y,pos.z, 0.0, -1.0, 0.0);

copyToCubeMapTexture(GL_TEXTURE_CUBE_MAP_NEGATIVE_X);

gluLookAt(pos.x, pos.y, pos.z, pos.x, pos.y,pos.z + 1.0, 0.0, -1.0, 0.0);

copyToCubeMapTexture(GL_TEXTURE_CUBE_MAP_POSITIVE_Z);

gluLookAt(pos.x, pos.y, pos.z, pos.x, pos.y,pos.z - 1.0, 0.0, -1.0, 0.0);

copyToCubeMapTexture(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);

gluLookAt(pos.x, pos.y, pos.z, pos.x, pos.y + 1.0,pos.z, 0.0, 0.0, +1.0);

copyToCubeMapTexture(GL_TEXTURE_CUBE_MAP_POSITIVE_Y);

gluLookAt(pos.x, pos.y, pos.z, pos.x, pos.y - 1.0,pos.z, 0.0, 0.0, -1.0);

copyToCubeMapTexture(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y);

//Restore matricesglMatrixMode(GL_MODELVIEW);glPopMatrix();glMatrixMode(GL_PROJECTION);glPopMatrix();

41

Page 43: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

//Restore viewportglViewport(0, 0, oldWidth, oldHeight);

Die Kopierfunktion muss wie beim ”normalen” Rendern einer Szene den Farb- undTiefenpuffer loschen und die Primitive aufrufen (hier ruft drawCubeMapScenedie Primitive auf), die gerendert werden sollen. Dabei darf das reflektierende oderrefraktierende Objekt nicht mitgezeichnet werden. Anstatt glutSwapBuffersnun aufzurufen, um das Bild im Fenster darzustellen wird die Cubemaptextur aus-gewahlt und mit glCopyTexSubImage2D das Bild in sie geschrieben:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//Jetzt darf das spiegelnde Objekt nicht//mitgezeichnet werden!drawCubeMapScene();

glEnable(GL_TEXTURE_CUBE_MAP);//Ziel Textur muss ausgewahlt werden//(die leere Cubemaptextur)selectCubeMapTexture(textureID);glCopyTexSubImage2D(cubeMapDirection,0, 0, 0, 0, 0, 512, 512);

glDisable(GL_TEXTURE_CUBE_MAP);

//glFinish();

glMatrixMode(GL_MODELVIEW);glLoadIdentity();

12.6 ”Hochladen” der Cubemap

glActiveTexture(GL_TEXTURE0 + textureUnit);glBindTexture( GL_TEXTURE_CUBE_MAP, ID);GLint loc;loc = glGetUniformLocation(program,"cubeMap");if(loc == -1)fprintf(stderr,"No such uniform named \"%s\"\n","cubeMap");

glUniform1i(loc, unit);

glActiveTexture(GL_TEXTURE0);

alernativ:

glActiveTexture(GL_TEXTURE0 + textureUnit);glBindTexture( GL_TEXTURE_CUBE_MAP, ID);

42

Page 44: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

shaderContainer->setSampler("cubeMap", textureUnit);

glActiveTexture(GL_TEXTURE0);

12.7 ”Hochladen” der restlichen Variablen

uniform float eta;uniform float fresnelPower;uniform mat4 camToWorld;

GLint loc;loc = glGetUniformLocation(program,"fresnelPower");if(loc == -1)fprintf(stderr,"No such uniform named \"%s\"\n","fresnelPower");

glUniform1f(loc, fresnelPower);

alternativ:

shaderConatiner->setUniform1f("fresnelPower",fresnelPower);

shaderConatiner->setUniform1f("eta", eta);shaderContainer->setUniformMatrix4fv("camToWorld", 1,false, cam2WorldArray);

12.8 Der Vertexshader

Funktionsweise des Vertexshaders:

• Transformation von Eckpunkt und Normale in Kamerakoordinaten.

• Berechnung des Anteils von Refraktion zu Reflexion durch die Approxima-tion von Schlick.

• Berechnung von Reflexions- und Refraktionsvektor (Kamerakoordinaten).

• Rucktransformation von Reflexions- und Refraktionsvektor in Weltkoordi-naten.

uniform float eta;uniform float fresnelPower;uniform mat4 camToWorld;varying vec3 reflectVector;varying vec3 refractVector;

43

Page 45: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

varying float ratio;...void berechneRefraktionsReflektionsVektoren(){//Transformation von Eckpunkt u. Normale ins//Kamerakoordinatensystemvec4 ecPosition = gl_ModelViewMatrix * gl_Vertex;vec3 ecPosition3 = ecPosition.xyz / ecPosition.w;vec3 i = normalize(ecPosition3);vec3 n = normalize(gl_NormalMatrix * gl_Normal);//Schlicks Fresnel - Approximationfloat f = ((1.0 - eta) * (1.0 - eta)) /((1.0 + eta) * (1.0 + eta));ratio = f + (1.0 - f) *pow((1.0 - dot (-i, n)), fresnelPower);//Berechnung von Refraktions- und ReflektionsvektorrefractVector = refract(i, n, eta);reflectVector = reflect(i, n);//RucktransformationrefractVector = vec3(camToWorld *vec4(refractVector, 1.0));reflectVector = vec3(camToWorld *vec4(reflectVector, 1.0));

}...

38

12.9 Der Fragmentshader

Funktionsweise des Fragmentshaders: Der Fragmentshader greift als erstes mitdem aus dem Vertexshader interpolierten Refraktionsvektor auf die dynamischeund statische Cubemap zu und erhalt dadurch zwei Farben. Da die statische Cube-map einen unendlich weit entfernten Hintergrund darstellt, werden mit dem Al-phawert der dynamischen Cubemap die beiden Texelfarben interpoliert. Der Al-phawert gibt also an, ob sich ein ein dynamisches Objekt zwischen dem Hinter-grund und der refraktierenden Oberflache befindet. Er ist nur am Rand der dy-namischen Objekte ungleich 1 oder 0, so dass es durch die Interpolation zu keinerSaumbildung am Rand kommt (wie es durch eine if-Abfrage, anstatt der Interpo-lation der Fall ware). Damit ist die Farbe der Refraktion bestimmt. Analog wirddie Farbe der Reflexion berechnet. Als letztes werden die Reflexions- und Refrak-tionsfarbe anhand des Ergebnis’ der Approximation von Schlick gemischt.

38vgl. [Ros06], S361

44

Page 46: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

varying vec3 reflectVector;varying vec3 refractVector;varying float ratio;uniform samplerCube staticCubeMap;uniform samplerCube dynamicCubeMap;...vec3 berechneReflexionsRefraktionsFarbe(){vec4 dynColor;vec3 statColor;

//Refraktionvec3 refractColor;dynColor = textureCube(dynamicCubeMap, refractVector);statColor = textureCube(staticCubeMap, refractVector);refractColor = dynColor.a * vec3(dynColor) +(1 - dynColor.a) * statColor;

//Relfexionvec3 reflectColor;dynColor = textureCube(dynamicCubeMap, reflectVector);statColor = textureCube(staticCubeMap, refractVector);reflectColor = dynColor.a * vec3(dynColor) +(1 - dynColor.a) * statColor;

return mix(refractColor, reflectColor, ratio);}...

39

13 Was ist mit dem Projekt noch moglich

• Partikelfarbanderung in Abhangigkeit von der Zeit.

• Kollision mit dem Boden.

• Verringerung des Alphawerts.

• Linien als Partikel.

• Das Erstellen der dynamischen Cubemap basiert auf der glCopyTexSubIm-age2D-Funktion, die zwar langsam ist, jedoch hat es den Vorteil, dass diese

39vgl. [Ros06], S.361 ff

45

Page 47: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

Funktion plattformunabhangig ist. Alternativ konnen Framebuffer-Objectsbenutzt werden. 40

• Benutzung von Point-Sprites (texturierte Partikel)

14 Bekannte Probleme

• Glut Scenefenster sollte eine Große von 512x512 nicht unterschreiten.

• Zu viele Varyingvariablen konnen auf ATI Karten zu Linkerfehlern fuhren.

• Wird bei der Zuweisung von den Texturen zu den Textureinheiten und derenZuweisung zu den Shadersamplern mehr als eine Textureinheit verwendet,sollte zum Schluss wieder Textureinheit 0 aktiviert werden. glActiveTex-ture(GL TEXTURE0);

• gl PointSize nicht zu groß setzen, da dies zum Einbruch der Bildwiederhol-rate fuhrt.

15 Fazit

Mit Shadern ist es moglich viele verschiedene Effekte in Echtzeit zu generieren,bei denen fruher eine Abwagung zwischen Performanz und Aussehen vorgenom-men und somit immmer irgendwo gespart werden musste. Dies wurde in dieserAusarbeitung anhand eines Shaders zum Rendern von Wolken und anhand eineszum Rendern von beiliebig großen, mit einer Wellenanimation versehenen Wasser-oberflachen untermalt. Um hierbei realistische Effekte zu erzielen, ohne dass dieEchtzeitfahigkeit verloren geht, sind Shader außerst hilfreich.

Die Grafikhardware entwickelt sich in einer rasanten Geschwindigkeit weiter,weswegen im Bereich der Shaderprogrammierung sicherlich noch interessante Ent-wicklungen zu erwarten sind. Gegenuber Losungen ohne Shaderprogrammierungist die Flexibilitat von Losungen mit Shadern weitaus hoher und deswegen in vie-len Bereichen außerst attraktiv und reizvoll. Durch Shader konnen fantastischeLosungen in Echtzeit erzeugt werden, die so ohne sie nicht immer oder zumindestnicht so leicht erreichbar waren.

Selbstverstandlich sind Shaderprogramme nicht in jedem Kontext der centralprocessing unit (CPU) uberlegen, doch eine Verwendung von Shadern sollte zu-mindest stets in Erwagung gezogen werden.

40vgl. [WLH07], S.615ff

46

Page 48: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

Abbbildungsnachweis

Abb.3 Yung-Feng Chi: True-to-Life Real-Time Animation of Shallow Water onToday’s GPU. In: [Eng06], Colorplate 12

Abb.4 Angelehnt an Tom Forsyth: Displacement Mapping. In [Eng042], S.77

Abb.5 Angelehnt an Yung-Feng Chi: True-to-Life Real-Time Animation of Shal-low Water on Today’s GPU. In: [Eng06], S.468

Abb.6 Angelehnt an Yung-Feng Chi: True-to-Life Real-Time Animation of Shal-low Water on Today’s GPU. In: [Eng06], S.469

Abb.7 Angelehnt an Yung-Feng Chi: True-to-Life Real-Time Animation of Shal-low Water on Today’s GPU. In: [Eng06], S.471

Abb.10, 12, 13 MAFA Funktionsplotter: http://www.mathe-fa.de/de#anchor

47

Page 49: Shaderbeispiele - userpages.uni-koblenz.decg/ss08/seminarER/Shaderbeispiele... · William Donnelly: Per-Pixel Displacement Mapping with Distance Functions. In: [Pha05], S. 125 6Das

References

[Apo00] Anthony Apodaca et.al.: Advanced RenderMan.Creating CGI for MotionPicture, San Francisco 2000

[Eng06] Wolfgang Engel (Hrsg.): Shader X4.Advanced Rendering Techniques,Hingham 2006

[Eng05] Wolfgang Engel (Hrsg.): Shader X3.Advanced Rendering with DirectXand OpenGL, Hingham 2005

[Eng041] Wolfgang Engel (Hrsg.): Shader X2.Introductions and Tutorials withDirectX 9, Plano 2004

[Eng042] Wolfgang Engel (Hrsg.): Shader X2.Shader Programming Tips andTricks with DirectX 9, Plano 2004

[Fos03] Ron Fosner: Real-Time Shader Programming. Covering DirectX 9.0, SanFrancisco 2003

[Kau03] Jan Kautz: Realistic, Real-Time Shading and Redering of Objects withComplex Materials, Saarbrucken 12003

[Ola02] Marc Olano et.al., Real-Time Shading, Natick 2002

[Pha05] Matt Pharr (Hrsg.): GPU Gems 2.Programming Techniques for High-Performance Graphics and General-Purpose Computation, Taunton 2005

[Shi05] Peter Shirley: Fundamentals of Computer Graphics, Wellesley 22005

[Stu06] Christian Stussak: Einblicke in die GPU-Programmierung,http://users.informatik.uni-halle.de/schenzel/ws06/Vortraege/GPU-Programmierung.pdf, Halle 2006, aufgerufen am 09.07.2008

[HoKno] Dennis Holzhauser, Benjamin Knopp: Shading Languages,http://pponkland.de/uni/files/CGSeminar.pdf, aufgerufen am 09.07.2008

[Ros06] Randi J. Rost. OpenGL(R) Shading Language (2nd Edition). Addison-Wesley Professional, January 2006.

[WLH07] Richard S. Wright, Benjamin Lipchak, and Nicholas Haemel.OpenGL(R) SuperBible: Comprehensive Tutorial and Reference (4th Edition)(OpenGL). Addison-Wesley Professional, June 2007.

48