[OpenGL] Echtzeittaugliche Blur-Effekte
Übersicht

![]() |
LobbyBetreff: [OpenGL] Echtzeittaugliche Blur-Effekte |
![]() Antworten mit Zitat ![]() |
---|---|---|
Um das vornweg klarzustellen, es werden keinerlei Kenntnisse zu OpenGL vorausgesetzt. Es geht schlichtweg um einen solchen Grafikeffekt:
(die Szene stammt aus einem Spiel das an dieser Stelle nebensächlich ist) Dieses Weichzeichnen lässt sich auch mit BlitzMax und Max2D echtzeittauglich realisieren. Eine Möglichkeit dazu werde ich im Folgenden aufzeigen. Die Erklärungen mögen nicht sonderlich tiefgreifend sein, dennoch habe ich mich für diesen Thread gegen das Codearchiv entschieden, weil ja doch ein erklärendes Element vorhanden ist, das über den Code hinaus geht. Die Methodik dahinter Zu erst einmal geht es um die simple Frage, wie man solche Verwischeffekte wie im Bild oben gezeigt, erzeugen kann - und das auch noch echtzeittauglich. Die Antwort hierrauf heißt Akkumulationspuffer. Das ist ein Bildpuffer, vergleichbar mit den Imagebuffern von Blitz3D. Das Besondere: Den Inhalt des Backbuffers kann man additiv auf den Inhalt des Akkumulationspuffers anwenden, zudem kann man den Akkumulationsbuffer wiederum in den Backbuffer ausgeben. Für den einzuspeisenden Backbuffer kann man zudem einen Helligkeitsfaktor angeben, sodass man auf die Helligkeit des Ergebnisses im Akkumulationspuffer Einfluss nehmen kann. Soweit so gut, doch was nutzt das? Im Falle des Weichzeichnens kann man nun so vorgehen, dass man die gesamte Szene als Bild auffasst, je um ein paar Pixel verschoben in den Akkumulationspuffer einspeist, und den Endzustand des Akkumulationspuffers als Ergebnis ausgibt. Schon wäre die gesamte Szene leicht verschwommen und besäße bei geeignet gewählten Helligkeitsfaktoren für das Einspeisen ungefähr auch noch die gleiche Helligkeit wie vorher. Nebenbei, der Akkumulationspuffer wird auch für Effekte wie Tiefenunschärfe und Antialiasing verwendet, ist also mit seiner einfachen Funktionsweise sehr vielseitig. Im Folgenden eine kleine Hilfsklasse die den Akkumulationspuffer in OpenGL etwas handlicher macht (TGLAccum.bmx). BlitzMax: [AUSKLAPPEN] Rem Kurz zur Verwendung, wenn man den Puffer nutzen will sollte man ihn zuerst mit Clear leeren, dann kann man mit add(fac:Float=1.0) und einem Faktor den Backpuffer additiv auf den Puffer anwenden so oft wie gewünscht. Schließlich gibt man mit Result(fac:Float=1.0) den Puffer in den Backpuffer aus. Der Akkumulationspuffer speichert jeden Farbwert übrigens in mehr als 8 Bit ab, sodass durch seine Verwendung die Anzahl der verschiedenen möglichen Farben nicht verloren gehen sollte. Screen to image Wer den vorherigen Abschnitt gelesen hat dürfte vielleicht bemerkt haben, dass man zuerst ein Bild von der Szene bräuchte, um so einen einfachen Unschärfeeffekt zu erzeugen (man könnte sie auch einfach mehrmals komplett, aber jedes mal ein wenig verschoben zeichnen, das würde sich anbieten wenn das noch performant genug wäre). BlitzMax bietet zwar eine Funktion GrabPixmap an, doch diese, inklusive dem Prozess um daraus wieder ein Bild zu machen, ist nicht gerade schnell wenn man den gesamten Grafikbereich damit erfassen will. Was also tun? Das Langsame an dem genannten Vorgang ist unter anderem der Umweg von der Grafikkarte in den Arbeitsspeicher (die Pixmap), und von dort wiederum zur Grafikkarte. Schneller geht es in OpenGL etwa, indem man den Backbuffer mittels glCopyTexImage2D in die Textur eines bestehenden TImages kopiert. Dabei wird zwar nicht die zum TImage gehörende Pixmap mit geändert, aber da wir im Folgenden nicht geplant haben diese zu verwenden, ist das auch nicht weiter wichtig. Hier also eine Kleine Hilfsklasse dafür (TScreenToImage.bmx). BlitzMax: [AUSKLAPPEN] Rem Für eigene Zwecke sollte es hier eigentlich ausreichen, die Methode do() ohne Parameter aufzurufen. Sie liefert schlicht ein TImage zurück, mit dem sich der aktuelle Inhalt des Backbuffers zeichnen lässt. Zu beachten ist, dass das zurückgegebene Bild an der Y-Achse gespiegelt ist, es also erst mit SetScale(1, -1) richtig herum dargestellt wird (das lässt sich bestimmt ganz leicht ändern, ist aber nicht so schlimm). Weichzeichnen So, und schon haben wir das Nötige um die oben gezeigten Weichzeichner zu implementieren. Ich gehe mal kurz darauf ein wie die drei gezeigten Arten erzeugt werden: Scaled Blur (vgl. Zoom Blur) Hierbei wird die Szene zu einem Punkt hin verschieden skaliert gezeichnet. Twisted Blur Hierbei zeichnet man die Szene zu einem Punkt hin gedreht. General Blur Das ist die bereits zu Anfang erwähnte Art, bei der die gesamte Szene unscharf wird indem man sie verschoben zeichnet. Die genannten Weichzeichner-Arten sind keine Fachtermini, sondern nur frei erfunden. Wenn man nun einen jeweiligen Blur-Effekt mit an sich kleiner Wirkung zeichnet, dies jedoch mehrmals hintereinander, dann wird der Effekt um so stärker (so sind auch die Bilder oben entstanden). Nun fehlt nur noch eine Klasse, die diese simplen drei Typen zur Verfügung stellt (TScreenEffect.bmx). BlitzMax: [AUSKLAPPEN] Rem Verwendung Nun, das wären schon alle Klassen um auf eine gegebene Szene ein paar Weichzeichner-Effekte anzuwenden. Da ich mich hier auf OpenGL beschränke, muss man vor dem Aufruf von Graphics entsprechend den Grafiktreiber auf GLMax2DDriver() setzen und den Accumbuffer aktivieren. Das könnte dann so aussehen. BlitzMax: [AUSKLAPPEN] SetGraphicsDriver(GLMax2DDriver(), GRAPHICS_BACKBUFFER | GRAPHICS_ACCUMBUFFER) Nicht vergessen, das muss vor Graphics aufgerufen werden, damit es eine Wirkung hat. Die Flags schon hier mit anzugeben ist sinnvoll, da der Accumbuffer so auch in Canvas-Gadgets der MaxGUI verwendet werden kann (und auch sonst an allen Orten, wo man sonst nicht nach den flags gefragt wird). Zu guter letzt noch ein Gesamtpaket das nochmal alle Klassen sowie ein Beispielprogramm enthält. Ob das Ganze tatsächlich Echtzeittauglich ist hängt von der Auflösung, der Anzahl der Iterationen sowie der Grafikkarte auf der das Programm läuft ab. Wenn ihr einen solchen Effekt verwenden wollt, dann bietet also unbedingt die Möglichkeit an, diese Effekte auszuschalten. Dieses Tutorial erhebt keinen Anspruch auf Richtigkeit, Vollständigkeit, Qualität und Funktionsweise des bereitgestellten Codes. Ich hoffe in Zukunft mehr BlitzMax Projekte mit solchen Grafikeffekten ausgestattet zu sehen und wünsche noch viel Spaß beim selbst Experimentieren. Lobby Divinus |
||
- Zuletzt bearbeitet von Lobby am Di, Jul 31, 2018 11:24, insgesamt 5-mal bearbeitet
PhillipK |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Coole sache. Auch wenn das Testprogramm auf höheren zoomstufen nervige Grafikfehler gibt, dennoch eine nette spielerei, um mal ohne shader ein paar weichzeichner einzubauen.
Störts dich, wenn ich das ganze nach c# portiere (OpenTK)? Mir steht grade der sinn nach spielerei ![]() |
||
![]() |
Lobby |
![]() Antworten mit Zitat ![]() |
---|---|---|
Danke dir, mach mit dem Code was du willst ![]() Nervige Grafikeffekte bei vielen Iterationen lassen sich über eine kleinere Zahl bei Quality erreichen (so heißt ein Parameter bei den Methoden scaledBlur, twistedBlur und blur in der Klasse TScreenEffect). Da dadurch aber auch die Zahl der Iterationen erhöht werden muss, um einen ähnlich starken Effekt zu erhalten, habe ich die Standardwerte für Quality möglichst groß gewählt. Bei hohen Auflösungen kann es auch sinnvoll sein, diese Zahl zu verkleinern. Wenn das allein nicht das gewünschten Effekt bringt, kann es auch sinnvoll sein die einzelnen Blur-Effekte manuell zu bearbeiten - bei Scaled Blur beispielsweise wird derzeit ja immer sowohl auf den Punkt zu als auch von dem Punkt weg skaliert. Würde man das Hinskalieren durch eine unskalierte Szene ersetzen, so könnte man bei diesem Effekt die Rechteckbildung vermeiden. Für Twisted Blur würde es sich anbieten die Basis von rotation in der Methode twistedBlur() kleiner zu wählen, vl. sogar auf ein expotentielles Wachstum zu verzichten. Die gezeigten Effekte lassen sich über den Backbuffer auch ohne Akkumulationspuffer erzeugen (was auf manchem Grafikkarten zudem schneller wäre), allerdings kann es dabei zu erheblichem Farbverlust kommen, zudem kann man nur schwer verhindern, dass dabei die Ränder dunkler werden. |
||
- Zuletzt bearbeitet von Lobby am Mi, März 20, 2013 11:57, insgesamt 3-mal bearbeitet
![]() |
Lobby |
![]() Antworten mit Zitat ![]() |
---|---|---|
Upps, einen Doppelpost wollte ich gar nicht. | ||
TheoTown - Eine Stadtaufbausimulation für Android, iOS, Windows, Mac OS und Linux |
PhillipK |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Ah sehr schön, damit hats das direkt geklärt *grins*
Bin grade ein wenig eingespannt, deswegen konnte ich mir den code nonet durchlesen. Hab ihn nur grob überflogen (wow: So wenig für so viel? cool!) Der Accumbuffer war mir bisher gänzlich unbekannt, ich hoffe, wenn ich den code portiere, lern ich ein wenig mehr ![]() |
||
![]() |
Lobby |
![]() Antworten mit Zitat ![]() |
---|---|---|
Habe nun zwei nette Dinge hinzugefügt:
Die TScreenEffect-Klasse kann nun auch die Blur-Effekte rein über den Backbuffer erzeugen. Das ist um Einiges schneller, erzeugt aber möglicherweise ungewünschte, dunkle Ränder und kann zu sichtbarem Farbverlust führen. Im Beispielsprogramm kann die Nutzung des Akkumulationspuffers über die Leertaste ein- und ausgeschaltet werden. Die Methoden zum Darstellen von Scaled- und Twisted Blur bieten jetzt Parameter x, y an, mit denen der Punkt um den der Effekt generiert werden soll, bestimmt werden kann. Im Beispielprogramm ist das der Mauszeiger. |
||
TheoTown - Eine Stadtaufbausimulation für Android, iOS, Windows, Mac OS und Linux |
Übersicht


Powered by phpBB © 2001 - 2006, phpBB Group