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
Dies ist, was ich erwarte (und was in paint.net passiert):
erwartetes Ergebnis
Offensichtlich lässt die Standard-Mischfunktion von opengl es so aussehen (sehr falsch):
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
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)
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)
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)
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
quelle
Antworten:
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.
Zur Vereinfachung der Anzeige werden hier die endgültigen RGB-Werte ausgegeben:
Und hier sind die endgültigen Transparenzwerte, die ausgegeben werden.
(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.
quelle
GL_ONE
auch so sein? Ansonsten sieht die Alpha-Gleichung so ausdest_alpha = src_alpha * src_alpha + 1 * dest_alpha
(0,0,0)
. Von Natürlich ist es dunkler als wenn man es bei 50% gegenüber mischen(255,255,255)
.finalAlpha = srcAlpha + destAlpha * (1 - srcAlpha)
undfinalColor = ((srcColor * srcAlpha) + (destColor * destAlpha * (1 - srcAlpha))) / finalAlpha
DasColor * Alpha
Bit 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 )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.
quelle