mein Problem resutiert wahrscheinlich aus einem Missverständnis beim Blending oder sowas und lässt sich daher hoffentlich schnell beseitigen, aber kommen wir zur Sache:
Ich versuche mich gerade daran, in 2D ein kleines Spiel zu programmieren. Dieses soll auf einer aus Quadraten zusammengesetzten Karte spielen. Außerdem benutze ich ein primitives Partikelsystem (welches sich ziemlich am Partikeltutorial orientiert), um Rauch oder Explosionen darzustellen.
Um einem allzu großen Codetohuwabohu vorzubeugen, habe ich mir nun eine kleine "Testumgebung" geschaffen, um die grafische Darstellung der Objekte, so wie ich sie später im Spiel verwenden möchte losgelöst vom eigentlichen Spiel erstmal zu testen. Ich wollte quasi mit der Grafik rumsauen und experimentieren, ohne dabei den eigentlichen Spielcode zuzumüllen.
Ein Bild einer (sehr einfallslosen) Testkarte in dieser Umgebung hab ich als Attachment angehangen (hoffentlich hats geklappt) - danaben sieht man eine Explosion, so wie ich sie gerne dargestellt hätte (mitten in der Animation fotografiert, darum recht unspektakulär). Beides für sich entspricht sehr gut meinen Vorstellungen. So weit, so gut.
Das Problem ist, dass die Explosionen (wie alle anderen Partikeleffekte auch) nur solange gut aussehen, wie ich sie vor dem schwarzen Hintergrund rendere - im Spielverlauf sollen sie aber natürlich auf der Karte auftreten - und dann werden sie mir viel zu "blass". Auch davon hängt ein Screenshot an.
Ich bin dann schon drauf gekommen, dass das daran liegen muss, dass ich, wie in dem Partikeltut beschrieben, additiv blende, und darum zur Farbe der Partikel auch die Farbe der Textur dahinter addiere - dadurch verschmilzt die Explosion mit der Karte und hebt sich nicht mehr gut davon ab.
Ich hab dann (eher planlos) mit anderen Blendingfunktionen experimentiert und bin irgendwann über glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); gestolpert - wie ihr euch denken könnt (ihr kennt euch ja hoffentlich mit Blending aus xD) kam das dem, was ich erreichen wollte schon näher - der Partikeleffekt wurde in voller Pracht über die Map gerendert. Leider klappte auchdas nur auf den ersten Blick, denn dadurch, dass die Farbwerte der einzelnen Partikel auch nicht mehr addiert wurden, war der Partikeleffekt nicht halb so schön. Auf nen Screenshot hab ich hier mal verzichtet.
Was ein verbissener OpenGL-Neuling ist gibt sich natürlich nicht geschlagen und probiert weiter (natürlich weiterhin planlos, denn mein Forenaccount war noch nicht aktiviert). Ich habs dann geschafft (wie steht unten - ist auch ein Zufallsprodukt), den Effekt komplett schwarz zu rendern (und die Karte auch damit schwarz zu "überrendern"). Das für sich schien mir erstmal nicht wie ein Erfolg, wurde aber zumindest optisch zu einem, nachdem ich auf die Idee gekommen war, über den nun schwarz gerenderten Effekt noch einmal in Farbe zu rendern. Screenshot ist unten.
Wenn einer von den "Profis" bis hierhin gelesen hat sehe ich ihn haareraufend vor meinem geistigen Auge, denn jeden Partikeleffekt doppelt zu rendern erscheint selbst mit als Neuling performancemässig suboptimal. Kurz gesagt - ich bin davon überzeugt, dass das einfacher und schneller gehen muss, habe aber nicht die geringste Ahnung wie.
Noch einmal kurz meine Anforderungen:
- Einzelne Partikel des Effekts sollen additiv geblendet werden
- Der Gesamteffekt soll farblich schließlich nicht vom Untergrund verfälscht werden
Ich hoffe, ich hab nicht einfach eine Kombination von zwei Konstanten bei glBlendFunc(); übersehen, die zum Erfolg geführt hätte...Ich hab auch wirklich versucht, überlegt an die Sache ranzugehen, aber jeder Versuch, aus den Erläuterungen zu den Parametern im Blendingtutorial auf das Ergebnis zu schließen wurde beim anschließenden Testen pulverisiert, so dass ich irgendwann wirklich planlos vorgegangen bin.
Achja, die verwendeten OpenGL-Einstellungen noch:
für den hässlichen, weil blassen Effekt:
Die Renderreihenfolge ist in beiden Fällen wie im Blending-Tutorial angegeben - erst das undurchsichtige (die Map) dann das durchsichtige (die Partikeleffekte)
Ich hatte mir zeitweilig übrigens schon überlegt, die Effekte mit aktiviertem additiven Blending jeweils in eine Textur zu rendern (Wie im Renderpass-Tutorial beschrieben), und diese dann an der richtigen Stelle mit irgendeiner anderen BlendFunc (die hätte ich schon gefunden o.O) über meine Map zu legen...dann müsste ich aber ja für jedes Rauchwölkchen, jede Explosion und jede Schockwelle jeweils eine Textur "vorrendern", zwsichenspeichern und schließlich über die Map rendern.
Und nun zum Schluss ein herzliches Danke an jeden, der sich bis hier durchgekämpft hat! Noch mehr Dank gibts dann für ne Lösung (möglichst einfach und möglichst gut dokumentiert, damit ich als Einsteiger die Herangehensweise nachvollziehen kann)
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.
Registriert: Mo Sep 02, 2002 15:41 Beiträge: 867 Wohnort: nahe Stuttgart
Hallo,
ich glaube dein Problem würde sich lösen lassen, wenn du deiner Textur einen Alphakanal spendierst und dann damit blendest.
Als Alphakanal eignet sich die Textur selber als Graustufen-Fassung, mit der glBitmap.pas lässt sich der mit AddAlphaFrom* relativ simpel auch aus einer Extra-Datei dazuladen ohne sich mit PNG rumschlagen zu müssen.
Bei glColor4f(R,G,B,1) dann als 4. Parameter 1 angeben, damit sichergestellt ist, dass der Alphakanal nicht verschluckt ist und dann mittels glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) blenden, sodass von deiner Partikeltextur-Quelle der Anteil, der geblendet wird, mit dem Alphakanal multipliziert wird und der Rest, wo die Textur schwächer erscheinen soll, vom Framebuffer übernommen wird.
Ansonsten bei längerem Nachdenken frage ich mich, ob nicht auch
glBlendFunc(GL_ONE, GL_ONE)
das gewünschte Ergebnis liefern müsste...
Registriert: Di Apr 29, 2008 18:56 Beiträge: 1213
Programmiersprache: Delphi/FPC
Hey,
nur GL_ONE geht nichm, weil er dann den Mittelwert von SRC un DST nimmt. Und er will ja wenn Alpah = 1 is nur das Partikle sehen. Also is das mit dem glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) schon richtig. Das Partikle an sich wird mit seinem Alphawert gezeichnet und wenn der Alphawert ab nimmt, dann soll die Szene dahinter gezeichnet werden.
Der Aufruf alleine sorgt dafür, dass auch die Farbwerte der Partikel untereinander nicht mehr addiert werden. Wenn das nicht passiert, dann sieht der Effekt aber leider nur noch halb so gut aus. Kurz: Die Farbwerte der Partikel sollen sich addieren, die von Partikeln und Hintergrund aber nicht.
Das sorgt dafür, dass die Partikel schwarz gerendert werden (das benutz ich im Moment ja auch, um beim ersten Rendern der Partikel den farblosen Hintergrund zu schaffen)
Registriert: Mo Sep 02, 2002 15:41 Beiträge: 867 Wohnort: nahe Stuttgart
Bergmann89 hat geschrieben:
nur GL_ONE geht nichm, weil er dann den Mittelwert von SRC un DST nimmt.
Das ist auch nicht ganz richtig, bei (GL_ONE, GL_ONE) werden Quelle und Ziel addiert (vorausgesetzt, BlendFunc = GL_ADD), aber nen Mittelwert wird da nirgends berechnet. Alles > 1 wird halt auf 1 zurückgeclampt.
Ich hätte jetzt aus dem Gedankenexperiment noch die Idee, zeichne den Hintergrund mit Alpha = 0 und die Partikel dann mit glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA).
Registriert: Fr Jan 04, 2008 21:29 Beiträge: 419 Wohnort: Lübeck
Es gibt im Wiki einen tollen Beitrag in dem nahezu alle nützlichen Kombinationsmöglichkeiten mit Bild erklärt werden. Bisher hat das immer funktioniert dort sein Wunschbild zu suchen und die angegebene Funktion einfach abzuschreiben.
Registriert: Do Sep 25, 2003 15:56 Beiträge: 7810 Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Naja, ganz so einfach wird das nicht. Wenn ich das hier lese:
Zitat:
Kurz: Die Farbwerte der Partikel sollen sich addieren, die von Partikeln und Hintergrund aber nicht.
Wenn ich das richtig verstehe, dann musst du die Partikel erst mit dem ersten Blendverfahren alleine in eine Textur rendern und dann mit dem anderen Blendverfahren über deine Szene blenden.
Ist es möglich den Tiefenpuffer aus der Orginalszene für das rendern in die Textur zu nutzen? Also das die Tiefeninfos aus der Szene auch beim Partikelrendern berücksichtigt werden? Für die Partikel selbst muss man den Tiefenpuffer nicht beschreiben, aber lesen.
_________________ Blog: kevin-fleischer.de und fbaingermany.com
Danke Flash, ich dachte schon, ich müsste das noch ein drittes Mal schreiben ^^
Das mit dem in eine Textur rendern klingt ja nach dem, was ich mir auch schonmal überlegt hatte. Irgendetwas hat mich von dem Verfahren bisher aber immer abgeschreckt - mal sehen, ob ich mich im Laufe der Woche da mal dransetze, bin sowieso im Moment noch etwas mit nem Umzug beschäftigt.
@ Tiefenpuffer:
Die Partikeleffekte sind vor wirklich jedem anderen Objekt in der 2D-Umgebung, um den Effekt in die Textur zu rendern bräuchte ich also (wenn ich alles richtig verstanden habe) die Tiefeninfos der Originalszene nicht, oder?
P.S.: Auch wenn der erste Satz so klingt - ich finds nich schlimm, dass mehrere Leute mit glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) kamen...es ist einfach zu offensichtlich
Der Alphawert der Map ist übrigens schon null und glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA) ist mächtig hässlich - die Alphamaske der Partikeltextur scheint dann nicht wirklich Beachtung zu finden - zumindest haben die Partikel alle nen schwarzen Kasten um sich rum.
Registriert: Mo Sep 02, 2002 15:41 Beiträge: 867 Wohnort: nahe Stuttgart
Zitat:
Der Alphawert der Map ist übrigens schon null und glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA) ist mächtig hässlich - die Alphamaske der Partikeltextur scheint dann nicht wirklich Beachtung zu finden - zumindest haben die Partikel alle nen schwarzen Kasten um sich rum.
Ja, diese Idee war murks. Du brauchst allerdings nicht zwangsweise einen weiteren Framebuffer.
Es würde reichen, zwei Renderpässe zu machen:
Damit wird im 1. Renderpass zuerst der Untergrund überall dort Schwarz geblendet, wo die Partikel hinsollen. Dann werden im 2. Renderpass auf dieses Schwarz alle Partikel additiv geblendet.
@WhiteHunter: Ich glaube das wurde oben schon geschrieben. Zudem wird dabei die Geschwindigkeit des Partikelsystems mal eben halbiert.
@zoiX: Ich denke die beste Lösung ist auf diese spezielle Blending-Art zu verzichten. Wenn du etwas an den Alpha-Wert, der Partikelanzahl, Partikelfarbe und sonstigen Parametern herumspielst müsstest du eigentlich entweder mit purem Alpha-Blending oder purem Additiven-Blending etwas sehr ähnliches hinbekommen.
Registriert: Fr Jan 04, 2008 21:29 Beiträge: 419 Wohnort: Lübeck
Ich glaube was gesucht ist in einem Fragment-Shader mittels Color = max(Src_Alpha*Src_Color,Dst_Alpha*Dst_Color); erreichbar. Dabei wird immer der hellste Punkt genommen, es wird aber nie heller als der hellste Texel des Partikels. Wie man das mit reinem Blending anstellen soll ist mir nicht ganz geläufig.
Registriert: Mo Sep 02, 2002 15:41 Beiträge: 867 Wohnort: nahe Stuttgart
@Coolcat: Verdammt. Jetzt fuchst mich das Problem nach längerem, eigenem Herumprobieren aber wirklich. Hoffentlich erzähl ich diesmal wenigstens was Neues.
Nebenbei, auch wenn halbe Performance drastisch klingt, so irre viele Partikel werden doch wohl nicht auf einmal gezeichnet werden, dass es derart in die Knie gehen wird.
Wenn es wirklich um maximale Performance geht, könnte man den Effekt auch (in mehrfacher Ausführung?) vorrendern (bspw. mit Sascha's Explosion-TexGen) und eine Textur davon zeitabhängig drüberblenden.
@Sellmann: In der Tat ist das, was du beschreibst, ...fast... auch mit Blending lösbar:
Code:
glBlendEquation(GL_MAX);
glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA);
Edit: Schonwieder Schwachsinn verzapft, BlendEquation = GL_MAX berücksichtigt die Alpha-Gewichtungsparameter ja gar nicht, sondern vergleicht nur der Werte wie sie sind.
Nebenbei, auch wenn halbe Performance drastisch klingt, so irre viele Partikel werden doch wohl nicht auf einmal gezeichnet werden, dass es derart in die Knie gehen wird.
Schon richtig. Da es sich hier um eine 2D-Anwendung handelt ist die Partikelanzahl wohl eher nicht das Problem. (Wenn ich Partikelsystem höre denke ich meist so an 100.000 oder 1 Mio. Partikel....die kann man auf der CPU gar nicht mehr verwalten....)
Naja, ich schätze, dass die mittlere Partikelanzahl später nur selten die 1000 überschreiten wird. Also ist die schon gefundene vielleicht tatsächlich die eleganteste Lösung. Schade eigentlich, ich hatte gehofft da was optimieren zu können....
@Coolcat - ich hatte tatsächlich probiert, an den Einstellungen für Farbe und so rumzuspielen, aber die Ergebnisse waren nie so zufriedenstellend wie das, was ich schon auf schwarzem Hintergrund gesehen hatte. Außerdem war da dieses "Es muss doch irgendwie gehen"-Gefühl...
@Whitehunter - Das das Problem einen fuchsen kann, dass weiß ich xD. Die Sache mit der anderen Blendequation hab ich der Vollständigkeit halber auch noch probiert...ich sag mal nix zum Ergebnis
@Sellmann - Wenn ich etwas mehr Erfahrung gesammelt hab werd ich auf die Shader-Idee sicher mal zurückkommen.
Also werd ich wohl dabei bleiben, die Geschichte mit zwei Renderpässen umzusetzen. Die gesamte Animation zuerst in ne eigene Textur zu rendern und die dann auszugeben ist mir ehrlich gesagt etwas zu kompliziert. Außerdem frage ich mich ernsthaft, ob das tatsächlich nen Performancegewinn bringen würde, oder ob die Methode eher noch langsamer wäre (in Hinblick darauf, dass die Partikelanzahl nicht in die paar-Tausende geht).
Mitglieder in diesem Forum: Google [Bot] und 4 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.