"Normaler" Mischmodus mit OpenGL-Problemen

8

Ich hatte große Probleme damit, eine OpenGL-Mischfunktion so zum Laufen zu bringen, wie ich es erwartet hatte (oder von einem vernünftigen Bildbearbeitungsprogramm). Als Beispiel verwende ich diese beiden Bilder zum Mischen (auf weißem Hintergrund etwas schwer zu erkennen, daher sind die Farben beschriftet):

Zu mischende Bilder

Bilder testen

Dies ist, was ich erwarte (und was in paint.net passiert):

erwartetes Ergebnis

Paint.Net Image Test

Offensichtlich lässt die Standard-Mischfunktion von opengl es so aussehen (sehr falsch):

glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

OpenGL Normal Blending Test

Nach einer Menge Tests ist dies der nächste Schritt, um eine "gute" Mischfunktion zu erstellen:

glBlendFuncSeparate (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA)

OpenGL Custom Blend Test

Wenn Sie jedoch auf das ursprünglich erwartete Ergebnis zurückblicken, werden Sie feststellen, dass einige der Farben etwas dunkler sind als sie sein sollten (mittlerer linker Teil). Insbesondere werden sie auf die Hälfte ihres Farbwerts vorvervielfacht (aufgrund des Alpha von 0,5), und ich kann anscheinend keine Funktion erstellen, die dies nicht tut (ohne seltsame Mischungsprobleme mit dem kaum sichtbaren roten transparenten Teil zu verursachen).

Kennt jemand eine Lösung für dieses Problem? Eine, die ich hatte, war, vormultipliziertes Alpha in den Quellen zu verwenden (obwohl ich dies nicht tun möchte, weil es zusätzliche Arbeit erfordert, um jede Farbe, die ich in meinem Spiel verwende, in vormultipliziertes zu konvertieren oder einfach ein paar Sachen in jeden Shader zu schreiben) und es so zu machen ::

glBlendFuncSeparate (GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA) (Keine Vormultiplikation)

OpenGL Custom Blend Test

Natürlich ist das auch falsch, aber dies ist tatsächlich das einzig richtige Ergebnis, das ich bisher erzielt habe:

glBlendFuncSeparate (GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA) (vormultiplizierte Eingaben)

OpenGL Custom Blend Test

Das einzige Problem ist, wie würde ich die Vormultiplikation beseitigen, um sie auf dem Bildschirm anzuzeigen? Es würde wahrscheinlich einen zusätzlichen Renderzyklus für jede Sache erfordern, die ich mische, und das scheint für dieses Problem viel zu komplex zu sein, daher suche ich immer noch nach einer Antwort (es ist interessant, dass ich nichts dazu finden kann, weil OpenGL so weit verbreitet ist, dass Ich würde mir vorstellen, dass jemand anderes auf dieses Problem gestoßen ist.

Quellen:

Online-Test der Mischfunktion - http://www.andersriggelsen.dk/glblendfunc.php
Bild der unteren Ebene - http://i.stack.imgur.com/XjLNW.png
Bild der oberen Ebene - http: //i.stack.imgur .com / 9CN6w.png

Zitronen Bonbon
quelle
Alle Screenshots stammen aus Anders Riggelsens Online- Tool Visual glBlendFunc + glBlendEquation . In Zukunft wäre es nützlich, solche Dinge zu erwähnen, wenn man um Hilfe bittet.
Trevor Powell
@ TrevorPowell Dang Ich wusste, dass ich vergessen habe, etwas zu sagen (ich hatte wirklich vor, das ganz unten zu setzen). So oder so ist es genau das, was ich verwendet habe, um Mischmodi einfach zu testen. Es sollte Standard für jede andere OpenGL-Art von Dingen sein (obwohl ich andere Leute sehen kann, die es verwenden möchten).
Lemon Drop

Antworten:

5

In Ihrem ersten Beispiel ( glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)) weisen Sie es an, Farben basierend auf dem Alpha des Bildes zu mischen, das oben gezeichnet wird (das "Vordergrund"). Wenn Sie also 50% zwischen der Vordergrundfarbe (38,50,168)und der Hintergrundfarbe (38,50,168)in der unteren linken Ecke des Bildes mischen , erhalten Sie nicht überraschend genau dieselbe Farbe (38,50,168). Weil diese Mischung genau das ist, was Sie OpenGL gesagt haben.

Gemessen an Ihrem "erwarteten" Bild möchten Sie keine Kreuzmischung zwischen den beiden Farben durchführen - Sie möchten die Vordergrundfarbe über die Hintergrundfarbe voller Stärke legen und nicht zwischen ihnen kreuzen.

Dazu möchten Sie glBlendFuncSeparate verwenden (da Sie die Hintergrundfarbe anders als das Alpha behandeln) und angeben, dass der Hintergrund-Alpha-Wert während des Mischvorgangs als 100% behandelt werden soll.

Arbeiten

Zur Vereinfachung der Anzeige werden hier die endgültigen RGB-Werte ausgegeben: RGB

Und hier sind die endgültigen Transparenzwerte, die ausgegeben werden. Alpha

(Dieser '100 %'-Transparenzbereich sollte tatsächlich als 99,7% transparent gekennzeichnet sein, und der untere rechte '50 %'-Bereich sollte als 49,7% transparent gekennzeichnet sein, beide aufgrund des rot getönten Bits auf der rechten Seite des ersten Bildes. Es tut uns auch leid, dass Sie Nummern mit "Transparenz" anstatt mit Deckkraft auflisten; möglicherweise etwas verwirrend.)

Wenn es bestimmte Probleme gibt, weisen Sie bitte auf den Bereich des RGB- oder des Alpha-Bildes hin, der falsche Werte erzeugt.

Trevor Powell
quelle
Sollte der Quell-Alpha-Koeffizient nicht GL_ONEauch so sein? Ansonsten sieht die Alpha-Gleichung so ausdest_alpha = src_alpha * src_alpha + 1 * dest_alpha
bcrist
Nun, wenn Sie es sich ansehen, ist das mittlere linke Stück immer noch viel dunkler als es sein sollte. Wenn Sie auch die Ebenen umdrehen , sieht es so aus: i.imgur.com/rigBNz6.png (das kaum sichtbare Rot ist da, um auf Dinge wie zu testen das
Lemon Drop
Sie mischen es zu 50% dagegen (0,0,0). Von Natürlich ist es dunkler als wenn man es bei 50% gegenüber mischen (255,255,255).
Trevor Powell
@TrevorPowell Sollte das nicht überhaupt eine Rolle spielen, wenn das Alpha 0 ist? Wie die Gleichungen, die ich anstrebe, sind wie folgt: finalAlpha = srcAlpha + destAlpha * (1 - srcAlpha)und finalColor = ((srcColor * srcAlpha) + (destColor * destAlpha * (1 - srcAlpha))) / finalAlphaDas Color * AlphaBit in der Farbberechnung kann in den Shadern durch Ausgabe vormultiplizierter Werte ausgeführt werden, aber es gibt keine Möglichkeit, durch die finalAlpha zu teilen, um die Vormultiplikation zu beseitigen. (Von hier genommen )
Lemon Drop
0

Ich hatte genau das gleiche Problem, als ich eine Reihe überlappender Framebuffer-Objekte wie Ebenen rendern wollte. Das Problem ist, dass die Open GL-Mischfunktionen linear sind und funktionieren, wenn der Zielhintergrund undurchsichtig ist. Die tatsächliche Mischungsgleichung zum Mischen von zwei transparenten Schichten ist jedoch keine lineare Gleichung und enthält einen Teilungsteil.

out_color = {src_color * src_alpha + dest_color * dest_alpha * (1-src_alpha)} / out_alpha

Ich denke nicht, dass dies mit aktuellen OpengGL-Implementierungen möglich ist. Um dies zu umgehen, musste ich einen Pixel-Shader verwenden, um die Ausgabe jedes Pixels manuell zu berechnen.

Supun Gothama
quelle
Ja, ich habe nur das Alpha auf den Texturen vormultipliziert, anstatt einige Problemumgehungen durchzuführen. Mit einigen Bibliotheken ist dies einfach (sie multiplizieren Texturen beim Laden nur vormultiplizieren)
Lemon Drop