Effektepfad

Aus DGL Wiki
Version vom 8. März 2010, 21:17 Uhr von Littledave (Diskussion | Beiträge) (Tiefenunschärfe-Artikel verlinkt)

Wechseln zu: Navigation, Suche

Effektpfad

Einführung

Willkommen zum Effektpfad. Dieser Pfad soll einen groben Überblick zum Erstellen von verschieden Effekt geben. Der Schwerpunkt dabei liegt eher in der Theorie als in der praktischen Anwendung. Somit sollte dieser Teil eher als eine Art Ideenansammlung anzusehen.

Viele erweiterte Effekte werden mit Shadern besonders einfach, schnell und flexibel umgesetzt. Daher ist es sinnvoll, sich mit Shadern auseinander zu setzen.

Effekttypen

Da es extrem viele verschieden Effekte gibt, wird hier erstmal zwischen zwei grundlegenden Effekttypen unterschieden: zum einen Lokale Effekte wie z.B. Feuer und Globale Effekte wie z.B. Post-Scene-Effekte.

Lokale Effekte

Zu dieser Kategorie gehören alle Effekte, die sozusagen eine Position in der virtuellen Welt haben. Angefangen von einfachen Funken über Wasserfälle bis hin zu einem kompletten Gewitter inklusive Wolken und prasselndem Regen.

Nun muss man sich erstmal überlegen, wie man solche Sachen darstellen könnte. Anhand des Wasserfalls kann man sich das mal ungefähr so überlegen: Im großen hat man bei einem Wasserfall extrem viele einzelne Wassertropfen und Wasserrinnen, die sich irgendwie gleich und doch chaotisch verhalten. Das gleiche Verhalten beschreibt z.B. die Schwelle zwischen dem flachen Wasser vor dem Wasserfall und dem freien Fall nach unten. Das chaotische Verhalten kann man beobachten, wenn man sich den Wasserfall nun genauer anschaut. Einzelne Tropfen fallen in verschiedenen Flugkurven nach unten und auch nicht immer genau in der Fließrichtung.

Anhand dieser Tatsache kann man erkennen, was der kleinste gemeinsame Nenner ist: der einzelne Wassertropfen. Da man nicht immer nur Tropfen darstellen will sondern vielleicht auf mal Funken oder ähnliches, muss man den Tropfen noch etwas abstrahieren. Somit kommt man auf den Partikel.

Zusammengefasst kann man sagen, dass ein Wasserfall einfach nur eine Ansammlung von Partikel ( die als Wassertropfen dargestellt werden) und sich dank der Schwerkraft immer schneller nach unten bewegen.

Ein Partikel

Ein Partikel ist die kleinste Einheit eines kompletten Effektsystems. Ein Partikel beschreibt dabei die Farbe, die Position, die Geschwindigkeit und noch weitere Eigenschaften eines einzelnen "Farbklecks" in der virtuellen Welt. Ein Effekt entsteht nun, wenn diese einzelnen Farbkleckse dynamisch und kontinuierlich erstellt und im Raum bewegt werden. Nun kommt man schon etwas weiter in die Richtung zur Realisierung eines Effekts. Man braucht als viele sich bewegende Partikel um einen bestimmten Effekt zu simulieren.

Partikel erzeugen, verwalten und darstellen

Da man sich nun die grobe Zielsetzung zur Partikelverwaltung überlegt hat, muss man sich nun überlegen, wie man das ganze realisiert. Einen guten Überblick dazu findet man im Artikel Partikelsysteme.

Einzelne Ermitter zu Effektsystemen zusammenfassen

Da man nun bereits einfache Effekte wie Feuer darstellen kann, kann man sich jetzt noch weitere Sachen überlegen. Wenn man nun beim Thema Feuer bleibt kann man erkennen, dass einfache Flammen für ein loderndes Feuer noch nicht ausreicht. Bei einem Feuer gibt es nicht nur eine Flamme, sondern z.B. auch Rauch und einzelne glühende Funken.

All diese einzelnen Teile eines Feuers kann man nun auch in einzelne Partikel-Emitter zusammenfassen. Diese Zusammenfassung muss dabei nicht nur eine Liste von einzelnen Emittern sein, sondern kann auch komplexere Ausmaße annehmen. Es kann z.B. eine Zeitabfolge eingebaut werden, mit der einzelne Emitter an- bzw. abgeschaltet werden. So kann man eine komplexe Explosion in einzelne aufeinander folgende Ereignisse aufteilen. Zuerst wird ein Emitter aktiviert, der einen großen Feuerball erzeugt. Dazu kommt dann noch ein Emitter, der viele kleine Partikel durch die Gegend schießen lässt. Nach kurzer Zeit aktiviert man dann einen Rauch-Emitter sowie einen kleineren Feuer-Emitter, die die beiden Explosions-Emitter ablösen. Im Programm selber kann man dann einfach die Zeitabfolge starten und schon hat man eine komplette Explosion auf dem Bildschirm.

Verbesserung der Darstellung

Wenn man nun ein bestehendes Effektsystem aufgebaut hat, kann man vor dem Problem stehen, dass die Darstellung noch nicht ganz perfekt ist. Ein fertiges Kochrezept zur Darstellungsverbesserung gibt es aber nicht, da es sehr unterschiedliche Ursachen haben kann, dass ein Effekt noch nicht so schön ausschaut. Daher gibt es hier nur ein paar kurze Tipps zu einzelnen Teilbereichen.

Partikel sortieren oder nicht

Es gibt mehrere Möglichkeiten, einzelne Partikel übereinander zu legen bzw. sie zu Blenden. Bei einem Feuer ist ein Additiver Blending-Mode sehr geeignet. Das heißt, dass der bisherige Farbwert im Framebuffer mit der Partikelfarbe zusammenaddiert wird. Je mehr Partikel es als an einem Punkt gibt, desto heller wird dieser. Anders schaut dies bei Rauch aus. Eine Rauchwolke wird normalerweise nicht heller, je dichter sie ist. Beim Rauch wird der dahinter liegende Teil eher immer weniger sichtbar. Somit ist beim Rauch ein subtrahierender Blending-Mode geeignet. Wenn man nun einen subtrahierenden Blending-Modus braucht, spielt die Reihenfolge beim Zeichnen eine große Rolle, da es sonst zu Darstellungsfehlern kommen kann.

Sollte man nun die Partikel wegen dem Blending-Modus sortieren müssen, muss man die Partikel von hinten nach vorne sortieren. Somit wird dann der Partikel, der am weitesten von der Kamera-Position ist, zuerst gezeichnet und der Partikel, der am nächsten an der Kamera-Position ist, zuletzt gezeichnet.

Soft-Partikel

Folgende Situation ist das Problem: ein Partikel ist an sich kein geometrisches Objekt sondern eher eine Art Durchschnittswert an einer bestimmten Position. Diese Vereinfachung lässt es überhaupt erst zu, Partikel-Effekte in Echtzeit darzustellen. Am Beispiel Rauch lässt sich das ganze gut erkennen. Ein Rauchpartikel ist meistens ein einfaches, graues Viereck mit einer Textur darauf. In Wirklichkeit ist es aber eine Ansammlung von vielen kleineren Elementen die mit der Umgebung interagieren und zusammen ein größeren "Rauchfleck" darstellen. Wenn man nun ein relativ großen Rauchpartikel als Viereck dargestellt hat, hat dieser nur zwei Dimensionen - in der Realität sind die einzelnen Elemente nicht nur in einer Ebene sondern komplett im Raum verteilt.

Die Illusion einer Teilchenwolke ist aber nur so lange perfekt bis das Viereck des Partikels ein anderes geometrisches Objekt in der virtuellen Welt schneidet. An diesem Schnittpunkt erkennt das menschliche Auge dann, dass es sich nur um ein einfaches Viereck handelt und der Wolkeneffekt ist nicht mehr vorhanden.

Bei Softpartikel wird jetzt folgendes gemacht: jedes Partikel wird mit einem Shader gezeichnet. In diesem Shader wird die Tiefe jedes Fragments des Vierecks mit der Tiefe der Karte bzw. der Szene verglichen. Je näher nun die Tiefe des Fragments der Szenen-Tiefe kommt, desto mehr wird das Fragment ausgeblendet. Mit diesem Trick gibt es keine harten Kanten mehr zwischen den einzelnen Partikel-Vierecken und der Geometrie.

Licht-Interaktion

Viele Partikel-Effekte sind selbst-leuchtend. Das heißt, dass sie selbst in der dunkelsten Ecke der Szene zu sehen sind. Eine Feuerflamme ist schließlich nicht nur dann sichtbar, wenn man sie mit der Taschenlampe anleuchtet. Anders schaut dies jedoch bei nicht-leuchtenden Partikeln wie z.B. Rauch aus. Wenn man in der virtuellen Welt in eine dunkle Ecke schaue, sieht man nicht, ob dort Rauch aus einem Abgasrohr kommt oder nicht. Erst wenn man den Rauch mit einem Licht anleuchtet, wird er sichtbar.

Somit kann man nicht generell davon ausgehen, dass man die Beleuchtung für Partikel nicht beachten muss. Daher ist es sinnvoll einem Emitter zu sagen, ob er Lichtinformationen braucht oder nicht. Wenn nun ein Emitter die Lichtinformationen braucht, sollte man für jeden Partikel einen Bumpmapping-Shader verwenden. Wenn man dies nicht macht, wirkt z.B. ein Rauchpartikel (welches ja eigentlich eine Rauchwolkte darstellen soll) flach und unnatürlich.

Verbesserung der Performance

Schöne Partikel-Effekte sind meistens sehr komplex, da meistens viele verschiedene Emitter mit einer relativ großen Anzahl von Partikeln dafür gebraucht werden. Damit die Performance des ganzen Systems durch die Effekte nicht zusammenbricht, sollte man versuchen, die Effekte z.B. nur zu zeichnen, wenn sie auch sichtbar sind.

Man nehme jetzt an, man stehe in einem Raum, an dessen Wänden viele Fackeln hängen. Wenn man jetzt in der Mitte des Raumes steht merkt man, dass man alle Fackeln, die sich hinter einem befinden, nicht sehen kann. Somit kann man sich für diese Fackeln das Zeichnen schon mal sparen. Das Problem ist hierbei natürlich die Frage, wie man diese Nicht-Sichtbarkeit berechnet. Man könnte natürlich die Sichtbarkeit jedes Partikels per Frustum-Check überprüfen. Jedoch würde das die Performance noch weiter verschlechtern als sie ohne Sichtbarkeits-Prüfung zu zeichnen. Sinnvoller ist es daher eher, ein Bounding Volume über jede Fackel zu setzen und zu überprüfen, ob sich dieses Volume innerhalb des View-Frustums befindet.

Da Partikel-Effekte dynamisch sind und sich somit auch ihre Größe bei jedem Frame ändern kann, muss man das Bounding Volume auch immer dynamisch berechnen. Als Bounding Volume eignet sich dabei entweder eine Bounding Sphere oder eine Axis Aligned Bounding Box. Um nun das Bounding Volume zu berechnen, speichert man bei der Berechnung der Partikel-Positionen den kleinsten sowie den größten Positions-Wert. Anhand dieser beiden Punkte lässt sich jetzt die Volume relativ einfach berechnen. Beide Volumes haben ihren Ursprung in der Mitte der beiden Punkte. Je nach Volume muss man jetzt noch die weiteren Parameter ausrechnen. Bei einer Kugel ist dann z.B. der Radius der Abstand zwischen einem der beiden Extrem-Punkte und dem Mittelpunkt der Kugel.

Globale Effekte

Zu dieser Kategorie gehören Effekte, die keine definierte Position in der virtuellen Welt haben. Stattdessen beeinflussen diese Effekte den ganzen Bildschirm und werden meistens erst nach dem Zeichnen angewendet. Daher werden diese Effekte meistens auch Post-Scene-Effekte genannt. Post-Scene-Effekte beeinflussen die Darstellung der virtuellen Welt bevor diese am Bildschirm angezeigt werden.

Weiter unten werden ein paar Beispiel-Effekte sowie deren theoretische Implementation gezeigt.

Allgemine Vorgehenweise

Bei Post-Scene-Effekten muss die Szene vorher in eine Textur gezeichnet werden. Dies wird meistens mit Frame-Buffer-Objects gemacht. Für den Einstieg reicht es meistens auch aus, die Szene mit glCopyTexImage in eine Textur zu kopieren.

Nachdem man nun die Szene in einer Textur hat, wird diese mit einem Full-Screen-Quad im orthogonalem Modus auf dem Bildschirm gezeichnet. Beim Zeichnen wird meistens ein Shader benutzt, der den Effekt dann darstellt.

Farbveränderungen

Ein relativ einfacher Effekt ist die Farbveränderung der Szene. Mit Hilfe eines Post-Scene-Effekts kann man die komplette Szene z.B. als Schwarz-Weiß-Bild darstellen lassen.

Mit Farbveränderungen kann man das Ambiente sehr steuern. Wenn man in einem Spiel eine Szene nachspielen soll, die sich in der Vergangenheit abgespielt hat, kann man dies mit Hilfe eines Schwarz-Weiß-Filters verdeutlichen. Oder man hat eine Zwischensequenz, die man optisch aufwerten will. So kann man z.B. die Farbwerte von Grün und Blau auf ein Schwarz-Weiß-Modell verändern und den roten Farbanteil gleich lassen. Somit lässt sich z.B. ein rotes Kleid sehr stark hervorheben.

Blur-Filter

Ein Blur-Filter zeichnet die Szene verschwommen, indem die Farbwerte eines Pixels durch die umliegenden Pixel beeinflusst wird. Je mehr umliegende Pixel den Farbwert des aktuellen Pixels beeinflussen, desto verschwommener wird das Bild.

Die einfachste Beeinflussung stellt die Durchschnittsberechnung dar. Dabei werden alle Farbwerte der Pixel zusammengezählt und danach durch die Anzahl geteilt. Eine bessere Berechnung kann mit der der Gauss-Funktion erreicht werden. Mit dieser Funktion beeinflussen näher gelegene Pixel das Ergebnis stärker als weiter entfernte Pixel.

Bloom-Filter

In der realen Welt gibt es dank der Sonne oder auf Grund von hellen Scheinwerfern Punkte, die extrem stark Beleuchtet werden. Wenn man sich solche Punkte anschaut, wird man geblendet. Dadurch kommt es einem so vor, als ob diese hell leuchtende Punkt andere, sich in der nähe befindliche, Punkte überstrahlt.

Dieses Phänomen kann man mit Hilfe eines Blooming-Filters nachbauen. Dabei wird die Szene erst in eine kleinere Textur gezeichnet. Diese Textur wird dann mit einem Blur-Filter weich gezeichnet. Durch das Verkleinern und das Verwischen soll das Überblenden simuliert werden.

Nun zeichnet man die gerade erstellte Textur mit additiven Blending über die normale Szene. Mit Hilfe eines Faktors kann dann noch die Intensität des Blooms eingestellt werden.

Beim Blooming sollte man das Überblenden nicht übertreiben, da der Effekt sonst unnatürlich wirkt und manchmal sogar schlechter aussieht als davor.

Depth-of-Field

Wenn man sich einen Photoapparat nimmt und ein Lineal schräg aus einer sehr nahen Distanz photographiert, wird man bemerken, dass nur der fokussierte Punkt (meistens in der Mitte) scharf ist. Der Teil des Lineals, der sehr nahe und der Teil, der weiter weg vom fokussierten Punkt ist, sind dagen unscharf - also verschwommen.

Diesen Photoeffekt kann man mit einem Post-Scene-Effekt ganz gut nachahmen. Dafür überlegt man sich erstmal, was für verschiedene Punkt der Szene gilt. Anhand des Lineals kann man sich das nun erarbeiten. Zuerst wird man bemerken, dass es einen Fokus-Punkt gibt. Dieser Fokus-Punkt hat eine Position sowie eine Tiefe. Um diesen Punkt herum verschwimmen dann die einzelnen Bereiche immer mehr. Dies hängt aber nicht nur von Distanz auf dem Bild ab, sondern vor allem von dem Tiefenunterschied zum Fokus-Punkt.

Zusammengefasst kann man sagen: je weiter sich der Tiefenwert eines Fragments von dem Tiefenwert des fokussierten Punktes unterscheidet, desto verschwommener ist dieses Fragment.

Da man nun weiß, was man braucht, kann man sich dan die Implementation wenden. Als erstes überlegt man sich, wie man die Stärke der Verwischung anhand der Parameter berechnen kann. Der Faktor lässt sich z.B. mit einer Exponentialfunktion berechnen, die als ersten Parameter die Tiefendistanz und als zweiten Parameter einen konstanten Faktor entgegen nimmt. Danach muss das aktuelle Pixel mit Hilfe eines Blur-Shaders verwischt werden. Die Intensität der Verwischung wird dabei über den gerade berechneten Faktor gesteuert.

Zusammenfassung

Um gute und schöne Effekte zu erzeugen, muss man einiges an Arbeit hineinstecken. In diesem Artikel konnten auf Grund der Komplexität von Effekten natürlich nicht nicht alle Möglichkeiten vorgestellt werden. Hoffentlich konnte jeder trotzdem ein paar Ideen sammeln.