PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Order-Independent Transparecy


Corrail
2004-08-06, 14:34:55
Mir ist da eine Idee für einen Algorithmus bezüglich der im Topic-Title angegebenen Rendering-Methode gekommen. Um das mal vorweg zu nehmen: der Algorithmus erfordert Floating Point Rendering Targets.

- Als erstes werden die Pixel normal mit deren Shader gerendert, allerdings nur alle undurchsichtigen Pixel (mit Alpha = 1).

- Dann werden die halb- und ganz durchsichtigen Pixel gerendert. Diese werden allerdings wie folgt im Framebuffer abgelegt: die End-Farbe (nur RGB, nicht A) wird mit dem entsprechenden Alpha-Wert multipliziert und mittels Blending (Normale Addition, glBlendFunc(GL_ONE, GL_ONE) in OpenGL) im Floating Point Frame-Buffer abgelegt.

- Wenn alles fertig gerendert ist kommt ein letzter Pass, wo ein Shader pro Pixel im Framebuffer operiert: er dividiert einfach die RGB Werte durch den Alpha-Wert.

Ich habe hier somit einen gewichteten Mittelwert erreicht. Es ist klar, dass es physikalisch nicht ganz korrekt ist. Würde trotzdem gerne wissen, was ihr dazu meint.

Xmas
2004-08-06, 14:43:53
Das wäre nicht nur nicht ganz Korrekt, sondern furchtbar falsch.

Wenn du eine undurchsichtige Oberfläche hast, und davor eine 50% transparente, dann sollte die Farbe sich ja zu gleichen Anteilen ergeben. Nach deiner Technik wäre es aber 2/3 der undurchsichtigen und 1/3 der durchsichtigen Oberfläche.

Corrail
2004-08-06, 14:52:26
Das stimmt schon, wenn man den Alpha-Wert wie das klassische Alpha-Blending (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) benutzt. Dort hieß es: Alpha = 0,5 => 0,5*Src-Farbe + 0,5*Dst-Farbe. Man müsste halt hier den Alpha-Wert neu definieren.
Außerdem ist mir schon klar, dass es keine 100%ig korrekte Blending Methode ist, weil es egal ist, ob ein mit 0,9 gewichtetes Pixel vor oder nach einem mit 0,1 gewichteten kommt. Es ginge mir nur darum ob es halbwegs was gleich schaut.

Xmas
2004-08-06, 15:33:24
Nein, ich denke es würde bei weitem nicht halbwegs gleich aussehen.

So wie ich deine Methode verstanden habe:
Undurchsichtiger Pixel wird geschrieben, z.B. RGBA(0, 0, 0, 1)

Zweiter Pass, transparente Pixel:
glBlendFuncSeparateEXT(GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ONE);
was effektiv src_rgb mit src_alpha multipliziert, auf den Framebuffer aufaddiert, und src_alpha mit dst_alpha addiert.
Halbdurchsichtiger Pixel wird geschrieben, z.B. RGBA(1,1,1,0.5)
Ergebnis im Framebuffer: RGBA(0.5, 0.5, 0.5, 1.5)

Dann in einem letzten Pass dividierst du RGB durch A im Framebuffer.
Ergebnis im Framebuffer: RGB(0.33, 0.33, 0.33)

Bei echtem Alpha-Blending wäre dagegen RGB(0.5, 0.5, 0.5) korrekt.

Corrail
2004-08-06, 15:39:42
Ja, genau so hab ich mir das gedacht. Aber man kann ja genauso hergehen und anstatt einem Alpha-Wert von 0.5 einen Alpha-Wert von 1.0 nehmen (wenn man 50% durchsichtigkeit haben will). Kommt man somit auf das gleiche Ergebnis. Ich habe ja gemeint, dass man hier die Bedeutung des "Alpha-Wertes" anders definideren müsste...

Xmas
2004-08-06, 16:06:11
Dann bräuchtest du z.B. Alpha = 99 für 99% Undurchlässigkeit. Allerdings würde das bei mehreren Transparenzlayern wieder nicht funktionieren. Aber genau das (und nur das) ist doch das Problem, das man mit Order-Independend Transparency lösen will. Wenn niemals zwei Transparenz-Layer übereinander liegen können, braucht man sich um die Reihenfolge gar keine Gedanken zu machen.

Corrail
2004-08-06, 16:52:41
Aber genau das (und nur das) ist doch das Problem, das man mit Order-Independend Transparency lösen will. Wenn niemals zwei Transparenz-Layer übereinander liegen können, braucht man sich um die Reihenfolge gar keine Gedanken zu machen.

Stimmt, da ist was dran. Von der Seite hab ich das noch gar nicht betrachtet... thx für deine Aufklärung ;)

RoKo
2004-08-07, 20:02:31
Oh, da muß ich doch gleich die Gelegenheit nutzen, um nach Eurer Meinung zu etwas, was ich mal in der Beziehung gemacht hatte, zu fragen:
Wahrscheinlich ist das schon ziemlich grundsätzlich falsch, aber ich habe mir überlegt, ein transparenter Gegenstand absorbiert einerseits Licht und andererseits reflektiert er Licht. Also habe ich statt die transparente Farbe mit der vorherigen zusammenzuknuddeln folgendes gemacht:

-alle nicht-transparenten Gegenstände rendern
-alle transparenten Gegenstände additiv mit der Farbe der eigenen Farbe draufblenden (Reflektion)
-alle transparenten Gegenstände nochmals subtraktiv mit der Komplementärfarbe draufblenden (Absorbtion)

Das ganze ist leider nur fast order-independent (da zwischendrin Werte < 0 oder > 1 herauskommen können). In der Praxis merkt man das aber selten und ich finde, es sieht ganz vernünftig aus.

Xmas
2004-08-07, 21:21:14
RoKo, auch diese Methode funktioniert nicht wie sie soll. Stell dir nur mal eine halbdurchlässige schwarze und eine halbdurchlässige weiße Fläche vor. Es hängt dann von der Reihenfolge ab, ob die resultierende Farbe eher weiß oder eher schwarz ist.

Farbige Transparenz ist sowieso so eine Sache, wenn man es korrekt machen wollte, müsste man ja mit Farbspektren rechnen.

Fakt ist, man kann die Reihenfolge nicht einfach aus der Rechnung ausschließen. Es ist nur möglich Techniken zu verwenden die die Reihenfolge sozusagen selbst ermitteln, und damit dem Programmierer das Sortieren abnehmen.

RoKo
2004-08-07, 23:52:36
RoKo, auch diese Methode funktioniert nicht wie sie soll. Stell dir nur mal eine halbdurchlässige schwarze und eine halbdurchlässige weiße Fläche vor. Es hängt dann von der Reihenfolge ab, ob die resultierende Farbe eher weiß oder eher schwarz ist.

Jep, siehe meine letzten beiden Sätze.

Aber führ das mit den Farbspektren doch mal genauer aus ;) Wollte schon immer mal wissen, wie man das korrekt machen würde. Gibt's vielleicht eine Seite, die das erklärt?

Was wäre eigentlich physikalisch gesehen korrekter? Das übliche GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA oder meine Metohde (beides jetzt sortiert)?

Xmas
2004-08-08, 02:38:24
Jep, siehe meine letzten beiden Sätze.
Aber es geht nicht um Werte außerhalb [0, 1], und der Unterschied ist IMO erheblich. In der Realität hängt es von der Reihenfolge ab, deine Methode würde beide Male dasselbe Ergebnis liefern.


Aber führ das mit den Farbspektren doch mal genauer aus ;) Wollte schon immer mal wissen, wie man das korrekt machen würde. Gibt's vielleicht eine Seite, die das erklärt?
Korrekterweise hätte fast jede Lichtquelle ein Farbspektrum, also unterschiedliche Intensität bei unterschiedlichen Wellenlängen. Monochromatisches Licht (nur eine einzige Wellenlänge) ist sehr selten. Ebenso hätte jedes Objekt ein Entsprechendes Absorptions- und Durchlass-Spektrum. Also z.B. 80% durchlässig für Licht von 500nm Wellenlänge, 50% für 550nm, usw.

Dabei ist die Lichtbrechung natürlich noch ganz außen vor gelassen. Außerdem reflektiert z.B. eine verrußte Glasscheibe mit 10% Durchlässigkeit ganz anders als eine mit dunklem Glas.

Was wäre eigentlich physikalisch gesehen korrekter? Das übliche GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA oder meine Metohde (beides jetzt sortiert)?
Schwer zu sagen, da IMO unterschiedliche Sachverhalte modelliert werden. Das lass ich mir später nochmal durch den Kopf gehen.