OpenGL: Transparenz

Kann man ein Objekt durch ein davorliegendes (teilweise) durchsichtiges Objekt hindurch sehen, spricht man von Transparenz. In OpenGL erzielt man diesen Effekt mittels Blending. Normalerweise werden weiter vorn liegende Objekte einfach über dahinterliegende Objekte gemalt. Sie verdecken diese vollkommen. Im Z-Buffer wird der aktuelle Tiefenwert für jeden Pixel der im Framebuffer gezeichnet wird abgelegt. Soll ein Pixel gezeichnet werden muss sein Tiefenwert kleiner sein, als jener der schon im Z-Buffer gespeichert ist. Sonst wird der Pixel nicht gezeichnet. Das gilt auch für transparente Objekte. Jedoch ersetzen sie den dahinterliegenden Farbwert nicht, sondern verändern ihn. Der resultierende Farbwert wird anhand einer Mischfunktion (blending function) aus beiden Farbwerten berechnet. In OpenGL braucht man folgendes Setup:

  1. glEnable(GL_BLEND)    // Blending einschalten
  2. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)    // Mischfunktion wählen

Ausgeschaltet wird mit glDisable(GL_BLEND).
Sehen wir uns die Mischfunktion genauer an. Als Source Pixel gilt jener Pixel, der gerade gezeichnet werden soll (transparenter Pixel). Der Destination Pixel wiederum ist schon im Framebuffer vorhanden und wird gerade überzeichnet. Die Mischfunktion definiert zwei Faktoren: GL_SRC_ALPHA entspricht dem Alphawert a des Source Pixel, der die Transparenz bestimmt (rgba). GL_ONE_MINUS_SRC_ALPHA ergibt sich zu 1 – GL_SRC_ALPHA (1 – a). Die Mischfarbe ergibt sich als Summe aus der Farbe des Source Pixels multipliziert mit a und der Farbe des Destination Pixel multipliziert mit 1 – a. Als Beispiel stelle man sich ein rotes Objekt rgba = {1.0, 0.0, 0.0, 1.0} hinter einem voll durchsichtigen weißen Objekt mit rgba = {1.0, 1.0, 1.0, 0.2} vor. Achtung, bei rgba Farbwerten gibt a normalerweise die Opazität (Undurchsichtigkeit) und nicht die Transparenz an: Transparenz = 1 – Opazität. Ein Objekt mit a = 0.0 ist also vollständig durchsichtig. In diesem Beispiel ergibt sich der Farbwert zu rgb = {1.0, 1.0, 1.0} * 0.2 + {1.0, 0.0, 0.0} * (1 – 0.2) = {1.0, 0.2, 0.2}. Das Ergebnis entspricht einem leichteren Rotton, der zu 80% durch das weiße Objekt hindurchscheint. Mathematisch findet hier eine lineare Interpolation zwischen beiden Farbwerten statt.
Tipp: OpenGL bietet weitere Mischfunktionen an. Für Transparenz wird diese jedoch am häufigsten verwendet.

Reihenfolge im Rendering

Das oben beschriebene Setup bildet die Grundlage für transparente Materialen. Es ist aber nicht ausreichend. Das Ergebnis hängt direkt von der Reihenfolge ab in welcher die Objekte die Rendering Loop durchlaufen. Ein Grund ist der Z-Buffer. Wird ein transparentes Objekt zuerst gezeichnet verhindert sein Tiefenwert, dass jegliche Objekte die hinter ihm liegen später gezeichnet werden können, da sie beim Vergleich des Tiefenwertes ausscheiden würden.
Ein anderer Grund ist die Mischfunktion. Ihre Parameter beziehen sich auf Source- und Destination Pixel, was direkt mit der Renderingreihenfolge verknüpft ist. Der Sourcepixel wird aktuell gezeichnet (später) und gibt den Wert für Transparenz des Blending an. Der Destination Pixel wurde bereits gezeichnet (früher) und steht schon im Framebuffer. Die Mischfarbe ist nur korrekt wenn das transparente Objekte NACH dem hinter ihm liegenden Objekt gezeichnet wird.
Ein einfacher Lösungsansatz hierfür sieht wie folgt aus: Im ersten Schritt wird das Schreiben der Tiefenwerte in den Z-Buffer (depth writing) für transparente Objekte ausgeschaltet. Dahinter liegende Objekte werden so – unabhängig von der Reihenfolge – immer gezeichnet. In OpenGL ist dies durch glDepthMask(FALSE) möglich. Achtung: Lesen im Z-Buffer bleibt weiterhin aktiviert. Im zweiten Schritt erfolgt eine Aufteilung aller Objekte einer Szene nach opaquem und transparentem Material. In der Rendering Loop werden dann zuerst die opaquen Objekte und erst im Anschluss die transparenten Objekte gezeichnet. Auf diese Weise findet eine korrekte Überblendung der opaquen Objekte unter Anwendung der Mischfunktion statt.

Fazit

Dieser Ansatz ist performant durchführbar und erzielt in den meisten Situationen korrekte Ergebnisse. Knifflig wird es sobald sich transparente Flächen gegenseitig verdecken. Dann ist eine Sortierung der transparenten Objekte untereinander nach ihrem Tiefenwert, also in Z-Richtung, notwendig. Dieses Problem performant zu lösen ist ein aktuelles Forschungsthema. Ein algorithmischer Ansatz hierfür ohne Sortierung ist Depth Peeling.

Mehr Wissen: Depth sorting alpha blended objects

Autor:    Michael Keutel | 28.04.2013

One Response so far.

  1. […] Licht, Farbe, Blendeffekte usw… gruss transparente zum Schluss. Hier ist es beschrieben: http://www.michaelkeutel.de/computer…s/transparenz/ "… In der Rendering Loop werden dann zuerst die opaquen Objekte und erst im Anschluss die […]