www.codeworx.org/opengl-tutorials/Tutorial 8: Einfache Transparenz

Lektion 8: Einfache Transparenz

Die meißten Spezialeffekte von OpenGL nutzen in irgendeiner Form Blending. Blending dient dazu die Farbe eines auf dem Bildschirm darzustellenden Pixels mit dem Pixel, der sich bereits an der Stelle befindet zu kombinieren. Wie die Farben kombiniert werden können hängt von dem Alpha Wert der Farben ab und/ oder der Blendingfunktion die genutzt wird. Alpha ist eine vierte Farbkomponente, die normalerweise an letzter Stelle definiert wird. In der Vergangenheit habt ihr GL_RGB benutzt, um eine Farbe mit 3 Komponenten zu definieren. GL_RGBA kann dazu benutzt werden einen zusätzlichen Alpha Wert zu definieren. Des weiteren nutzen wir jetzt glColor4f() anstatt glColor3f().

Die meißten Leute stellen sich den Alpha Wert als eine Angabe vor wie eine solide ein Material ist. Ein Alpha Wert von 0.0f würde bedeuten das Material wäre vollständig durchsichtig. Ein Wert von 1.0f wäre vollständig undurchsichtig.

Die Blending Gleichung

Wenn ihr nicht so fit in Mathe seid und nur wissen wollt wie Tranzparenz praktisch funktioniert dann überspringt diese Sektion. Wenn ihr aber genau wissen wollt wie Blending funktioniert, dann sollte euch dieser Abschnitt interessieren.

(Rs Sr + Rd Dr, 
 Gs Sg + Gd Dg, 
 Bs Sb + Bd Db, 
 As Sa + Ad Da) 
OpenGL wird das Blending von zwei Pixeln auf der Basis der oben genannten Formel durchführen. Die s und r bezeichner stellen den ursprünglichen und den dazukommenden Pixel dar. Die S und D Komponenten sind die Blending Faktoren. Diese Werte drücken aus in welcher Form ihr die Pixel blenden wollt. Die häufigsten Werte für S und D sind (As, As, As, As) (oder auch die Alpha der Quelle) für S und (1, 1, 1, 1) - (As, As, As, As) (oder auch eins minus der Alpha der Quelle) für D. Dies erweitert die Blendingfunktion auf folgende Weise:
(Rs As + Rd (1 - As), 
 Gs As + Gd (1 - As), 
 Bs As + Bs (1 - As), 
 As As + Ad (1 - As)) 

Diese Formel wird als Ergebnis einen transparenten Effekt haben.

Blending in OpenGL

Wir aktivieren Blending wie alles andere auch. Dann wählen wir die Art der Gleichung und deaktivieren den Depth Buffer, denn wir wollen ja das die Objekte hinter unseren durchsichtigen Flächen immer noch gezeichnet werden. Das ist zwar nicht der offizielle Weg wie man lichtdurchlässige Flächen zeichnet, aber die meißte Zeit wird es prima funktionieren.

Rui Martin fügt hinzu: Der korrekte Weg ist alle transparenten Polys (mit einem Alpha unter 1.0) nach dem zeichnen der sonstigen Szene darzustellen und zwar in umgekehrter Reihenfolge ihrer Tiefe (das am weitesten entfernte zuerst).

Dies liegt daran das wenn man 2 Polygone (1 und 2) in unterschiedlicher Reihenfolge zeichnet man auch unterschiedliche Ergebnisse bekommt. Davon ausgehend das Polygon 1 näher am Betrachter liegt wäre es korrekt erst Polygon 2 zu zeichnen und dann erst Polygon 1. Wenn man sich die Realität ansieht kommt das Licht meißt von hinten (also hinter den 2 transparenten Polys) und muß erst durch Poly 2 und dann durch Poly 1 bevor es das Auge des Betrachters erreicht.

Ihr solltet DIE TRANSPARENTEN POLYGONE NACH TIEFE SORTIEREN und sie zeichnen NACHDEM DIE GANZE SZENE DARGESTELLT WURDE und mit aktiviertem Depth Buffer oder ihr werdet falsche Ergebnisse bekommen. Ich weiß das dies manchmal nervig ist, aber dies ist nun mal der korrekte Weg.

Wir nutzen den Code von Kurs 7. Wir beginnen indem wir zwei neue Variablen deklarieren. Ich gebe aber die ganze Sektion noch einmal an.


#include <windows.h>	// Header File For Windows
#include <gl\gl.h>	// Header File For The OpenGL32 Library
#include <gl\glu.h>	// Header File For The GLu32 Library
#include <gl\glaux.h>	// Header File For The GLaux Library

static HGLRC hRC;	// Permanent Rendering Context
static HDC hDC;		// Private GDI Device Context

BOOL	keys[256];	// Array Used For The Keyboard Routine
BOOL	light;		// Lighting ON/OFF
BOOL	lp;		// L Pressed?
BOOL	fp;		// F Pressed?
BOOL    blend;		// Blending OFF/ON?
BOOL	bp;		// B Pressed?

GLfloat	xrot;		// X Rotation
GLfloat	yrot;		// Y Rotation
GLfloat xspeed;		// X Rotation Speed
GLfloat yspeed;		// Y Rotation Speed

GLfloat	z=-5.0f;	// Depth Into The Screen

GLfloat LightAmbient[]=  { 0.5f, 0.5f, 0.5f, 1.0f };
GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat LightPosition[]= { 0.0f, 0.0f, 2.0f, 1.0f };

GLuint	filter;		// Which Filter To Use
GLuint	texture[3];	// Storage for 3 textures
Schaut euch mal den folgenden Ausschnitt des Codes an. Er steht ganz am Ende des 7. Teils.
if (keys[VK_LEFT])
{
	yspeed-=0.01f;
}
Direkt unter diesen Abschnitt werden wir die folgenden Zeilen hinzufügen. Sie dienen dazu zu überwachen ob die Taste "B" gedrückt wurde. Wenn ja, dann soll geprüft werden, ob blending bereits aktiviert ist. Wenn nein wird es aktiviert.

  if (keys['B'] && !bp)
  {
    bp=TRUE;
    blend = !blend;
    if(blend)
    {
      glEnable(GL_BLEND);	// Turn Blending On
      glDisable(GL_DEPTH_TEST);	// Turn Depth Testing Off
    }
    else
    {
      glDisable(GL_BLEND);	// Turn Blending Off
      glEnable(GL_DEPTH_TEST);	// Turn Depth Testing On
    }
  }
if (!keys['B']) { bp=FALSE; }

Aber wie können wir die Farbe bestimmen, wenn wir eine Textur benutzen? Ganz einfach, im modulierten Texturmodus wird jeder Pixel, der auf eine Fläche gemapped wird multipliziert mit dem Wert der bisherigen Farbe. Wenn also die zu zeichnende Farbe 0.5,0.5,0.4 ist multiplizieren wir sie mit der Anzahl der Farben und wir bekommen 0.5,0.6,0.4,0.2 (Alpha wird als 1.0 gewertet wenn nichts angegeben ist).

Das ist es auch schon. Blending ist eigentlich ganz simpoel in OpenGL.

(Anmerkung 11/13/99)

Ich (NeHe) habe den Blending Code so modifiziert das das Ergebnis der Objekte etwas eher so aussieht wie man es erwartet. Alpha Werte für die Quellen und das Ziel zu verwenden um Blending zu erreichen erzeugt Artefakte. Das bedeutet das die fortgewandten Seiten ebenso wie die seitlichen Flächen dunkler wirken. Im großen und ganzen wird das Objekt ziemlich verhunzt aussehen. Die Art wie ich Blending nutze ist vielleicht nicht die beste, aber sie funktioniert und das Objekt sieht so aus, wie es sollte wenn man die Belichtung aktiviert. Danke an Tom für den ursprünglichen code. Die Art wie er Blending nutzt ist der korrekte Weg mit Alpha Werten zu rechnen, aber es sah nicht wirklich so aus wie es sich die Leute vorstellten ;).

Der Code wurde noch einmal verändert, um ein Problem zu umgehen das einige Grafikkarten mit glDepthMask() hatten. Es scheint so als ob dieser Befehl bei manchen Karten DepthBufferTesting aktiviert und deaktiviert, also bin ich wieder zum guten alten glEnable und der Deaktivierung des DepthTesting zurüchgekehrt.

Alpha von Texture Maps

Der Alpha Wert der für die Transparenz genutzt wird kann von einer Texture Map genauso genutzt werden wie von einer durchgehenden Farbe. Um dies zu tun benötigt ihr einen Alpha Wert in eurem Bild welches ihr ladet und nutzt dann GL_RGBA als Farbformat im Aufruf der glTexImage2D().

Fragen?

Wenn ihr Fragen habt zögert nicht mich unter stanis@cs.wisc.edu. zu kontaktieren.

Tom Stanis

Die Source Codes und Ausführbaren Dateien zu den Kursen liegen auf der Neon Helium Website

Übersetzung von Delax & ChaosAngel/ Sundancer Inc.

(Präsentiert von www.codeworx.org)