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)