NeHe - Lektion 08 - Blending

Lektion 8



Einfache Transparenz

Die meisten Spezialeffekte in OpenGL basieren auf einer Art Blending. Blending wird benutzt, um die Farbe eines bestimmten Pixels, der gezeichnet werden soll, mit einem Pixel, der bereits auf dem Bildschirm ist, zu kombinieren. Wie die Farben kombiniert werden basiert auf dem Alpha Wert der Farben und/oder die Blending Funktion, die benutzt wird. Alpha ist die 4te Farbkomponente, die normalerweise an letzter Stelle spezifiziert wird. In der Vergangenheit haben Sie GL_RGB benutzt, um Farben mit 3 Komponenten zu spezifizieren. GL_RGBA kann benutzt werden, um auch Alpha zu spezifizieren. Zusätzlich können wir glColor4f() statt glColor3f() benutzen.

Die meisten Leute stellen sich Alpha als einen Wert vor, der angibt, wie durchsichtig das Material ist. Ein Alpha-Wert von 0.0 bedeutet, dass das Material komplett transparent ist. Ein Wert von 1.0 würde totale Undurchsichtigkeit bedeuten.

Die Blending Gleichung

Wenn Sie Mathe nicht mögen und Sie nur wissen wollen, wie das mit der Transparenz funktioniert, können Sie diesen Teil überspringen. Wenn Sie wissen wollen, wie Blending funktioniert, dann ist dieser Abschnitt genau das richtige für Sie.

(Rs Sr + Rd Dr, Gs Sg + Gd Dg, Bs Sb + Bd Db, As Sa + Ad Da)

OpenGL berechnet das Ergebnis des Blendings der zwei Pixel basierend auf dieser Gleichung durchführen. Das s und d beschreiben den Quell- und den Ziel-Pixel. Die S und D Komponenten sind die Blend-Faktoren. Diese Werte indizieren, wie Sie die Pixel blenden wollen. Die häufigsten Werte für S und D sind (As, As, As, As) (auch bekannt als Quell Alpha) für S und (1, 1, 1, 1) - (As, As, As, As) (auch bekannt als 1 minus Quell-Alpha) für D. Daraus resultiert eine Blending-Gleichung, die wie folgt aussieht:

(Rs As + Rd (1 - As), Gs As + Gd (1 - As), Bs As + Bd (1 - As), As As + Ad (1 - As))

Diese Gleichung hat als Ergebnis Transparente/Lichtdurchlässige Effekte.

Blending in OpenGL

Wir aktivieren Blending wie alles anderes auch. Dann setzen wir die Gleichung und deaktivieren das Schreiben in den Depth Buffer solange wir transparente Objekte zeichnen, da wir die Objekte, die hinter der durchsichtigen Fläche sind, auch noch zeichnen wollen. Das ist nicht der korrekte Weg für Blending, aber bei den meisten einfachen Objekten funktioniert das wunderbar. Rui Martins fügt hinzu: Der korrekte Weg ist, alle transparenten Polygone (mit Alpha <1.0) zu zeichnen, nachdem Sie die komplette Szene gezeichnet haben und diese in umgekehrter Tiefen-Ordnung (das entfernteste als erstes) zu zeichen. Das liegt daran, dass beim blenden zweier Polygone (1 und 2) in verschiedener Reihenfolge, es verschiedene Ergebnisse gibt, z.B. angenommen Polygon 1 ist am nähsten zum Betrachter, der korrekte Weg wäre, Polygon 2 als erstes zu zeichnen und dann Polygon 1. Wenn sie drauf schauen, kommt das Licht, wie in der Realität von hinten (hinter der 2 Polygonen, die transparent sind) und muss Polygon 2 als erstes und dann Polygon 1 passieren, bevor es das Auge des Betrachters erreicht. Sie sollten DIE TRANSPARENTEN POLYGONE DER TIEFE NACH SORTIEREN und sie NACHDEM DIE GESAMTE SZENE GEZEICHNET WURDE zeichnen, mit AKTIVIERTEN DEPTH BUFFER oder Sie erhalten unkorrekte Ergebnisse. Ich weiß, dass das manchmal nervig ist, aber das ist der korrekte Weg.

Wir werden den Code aus dem letzten Tutorial benutzen. Wir starten mit dem Hinzufügen zweier neuer Variablen am Anfang des Codes. Ich werde den kompletten Code-Ausschnitt der Klarheit halber hier nochmal komplett neu schreiben.

#include <windows.h>                    // Header Datei für Windows

#include <stdio.h>                    // Header Datei für die Standard Ein-/Ausgabe
#include <gl\gl.h>                    // Header Datei für die OpenGL32 Library

#include <gl\glu.h>                    // Header Datei für die GLu32 Library

#include <gl\glaux.h>                    // Header Datei für die GLaux Library


HDC        hDC=NULL;                // Privater GDI Device Context
HGLRC        hRC=NULL;                // Permanenter Rendering Context
HWND        hWnd=NULL;                // Enthält unser Fenster-Handle
HINSTANCE    hInstance;                // Enthält die Instanz der Applikation

bool    keys[256];                    // Array das für die Tastatur Routine verwendet wird
bool    active=TRUE;                    // Fenster Aktiv Flag ist standardmäßig auf TRUE gesetzt
bool    fullscreen=TRUE;                // Fullscreen Flag ist standardmäßig gesetzt
bool    light;                        // Beleuchtung AN/AUS
bool    blend;                        // Blending AUS/AN? ( NEW )
bool    lp;                        // L gedrückt?
bool    fp;                        // F gedrückt?
bool    bp;                        // B gedrückt? ( NEU )

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

GLfloat    z=-5.0f;                    // Tiefe in den Bildschirm hinein

GLfloat LightAmbient[]=  { 0.5f, 0.5f, 0.5f, 1.0f };    // Ambiente Licht Werte
GLfloat LightDiffuse[]=     { 1.0f, 1.0f, 1.0f, 1.0f };    // Diffuse Licht Werte
GLfloat LightPosition[]= { 0.0f, 0.0f, 2.0f, 1.0f };    // Licht Position

GLuint    filter;                        // Welcher Filter benutzt werden soll
GLuint    texture[3];                    // Speicher für 3 Texturen

LRESULT    CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);    // Deklaration für WndProc

Gehen Sie runter zu LoadGLTextures(). Finden Sie die Zeile: if (TextureImage[0]=LoadBMP("Data/Crate.bmp")). Ändern Sie sie in die folgende Zeile. Wir benutzen statt der Kisten-Textur für dieses Tutorial eine Glas-artige Textur.

    if (TextureImage[0]=LoadBMP("Data/glass.bmp"))    // Lädt das Glass Bitmap ( MODIFIZIERT )

Fügen Sie die folgenden zwei Zeilen irgendwo in den InitGL() Code ein. Diese Zeilen setzen die Helligkeit des zu zeichnenden Objekts auf volle Helligkeit mit 50% Alpha (Undurchsichtigkeit). Das bedeutet, wenn Blending aktiviert ist, ist das Objekt zu 50% Transparent. Die zweite Zeile setzt die Blending-Art, die wir benutzen wollen.

Rui Martins fügt hinzu: Ein Alpha Wert von 0.0 würde bedeuten, dass das Material komplett Transparent ist. Ein Wert von 1.0 würde totale Undurchsichtigkeit bedeuten.

    glColor4f(1.0f,1.0f,1.0f,0.5f);            // Volle Helligkeit, 50% Alpha ( NEU )
    glBlendFunc(GL_SRC_ALPHA,GL_ONE);        // Blending Funktion für Durchsichtigkeit basiered auf dem Quell Alpha Wert ( NEU )

Schauen Sie sich die folgende Code-Sektion an, die ganz am Ende von Lektion 7 gefunden werden kann.

    if (keys[VK_LEFT])                // Wurde die linke Pfeil-Taste gedrückt?
    {
        yspeed-=0.01f;                // Wenn ja, dekrementiere yspeed
    }

Direkt unter den obigen Code, wollen wir folgende Zeilen einfügen. Die unteren Zeilen überprüfen, ob die Taste 'B' gedrückt wurde. Wenn sie gedrückt wurde, wird überprüft, ob Blending ein- oder ausgeschaltet ist. Wenn Blending eingeschaltet ist, wird es ausgeschaltet. Ist Blending ausgeschaltet, wird es eingeschaltet.

    if (keys['B'] && !bp)                // Ist Taste B gedrückt und bp gleich FALSE?
    {
        bp=TRUE;                // Wenn ja, setze bp auf TRUE
        blend = !blend;                // Tausche den Status von blend auf TRUE / FALSE    
        if(blend)                // Ist blend gleich TRUE?
        {
            glEnable(GL_BLEND);        // Schalte Blending ein
            glDisable(GL_DEPTH_TEST);    // Schalte Depth Testing aus
        }
        else                    // Ansonsten
        {
            glDisable(GL_BLEND);        // Schalte Blending aus
            glEnable(GL_DEPTH_TEST);    // Schalte Depth Testing an
        }
    }
    if (!keys['B'])                    // Wurde die B Taste losgelassen?
    {
        bp=FALSE;                // Wenn ja, wird bp auf FALSE gesetzt
    }

Aber wie können wir die Farbe spezifizieren, wenn wir eine Textur-Map benutzen? Ganz einfach, im modulierten Texturmodus wird jeder Pixel der auf die Textur gemapped wird mit der aktuellen Farbe multipliziert. Wenn die zu zeichnende Farbe also (0.5, 0.6, 0.4) ist, multiplizieren wir sie mit der Anzahl der Farben und wir erhalten (0.5, 0.6, 0.4, 0.2) (es wird dabei angenommen, dass Alpha gleich 1.0 ist, wenn nichts angegeben ist).

Das war's! Blending ist eigentlich ganz einfach in OpenGL zu realisieren.

Anmerkung (11/13/99)

Ich ( NeHe ) habe den Blending Code so modifiziert, so dass das Ergebnis der Objekte eher so aussieht, wie es eigentlich soll. Verwendet man Alpha Werte für die Quelle und das Ziel, um Blending zu erzeugen, werden Artefakte erzeugt. Diese lassen die hinteren Seiten dunkler erscheinen, ebenso wie die seitlichen Seiten. Grundsätzlich würde das Objekt recht verhunzt aussehen. Die Art wie ich Blending benutze, mag nicht der Beste sein, aber es funktioniert und das Objekt erscheint so, wie es aussehen soll, wenn die Beleuchtung aktiviert ist. Danke an Tom für den ursprünglichen Code, die Art wie er Blending benutzte war der korrekte Wert, um mit Alpha-Werten zu blenden, aber es sah nicht so attratktiv aus, wie es die Leute erwartet haben ;).

Der Code wurde nochmal etwas verändert, um Adressierungsprobleme die einige Grafikkarten mit glDepthMask() hatten, zu umgehen. Es sieht so aus, dass dieser Befehl auf einigen Karten den Depth-Buffer-Test nicht korrekt aktivieren und deaktivieren, weshalb ich zurück zum guten alten glEnable und glDisable zurückgekehrt bin, um Depth zu testen.

Alpha aus Texture Maps.

Der Alphawert, der für die Transparenz genutzt wird, kann aus einer Texture Map gelesen werden, genauso wie eine Farbe. Dafür benötigen Sie einen Alphawert in Ihrem Bild, dass Sie laden wollen und benutzen dann GL_RGBA als Farbformat im Aufruf von glTexImage2D().

Fragen?

Wenn Sie irgend welche Fragen, kontaktieren Sie mich über stanis@cs.wisc.edu.

Tom Stanis

Jeff Molofee (NeHe)

* DOWNLOAD Visual C++ Code für diese Lektion.

* DOWNLOAD Borland C++ Builder 6 Code für diese Lektion. ( Conversion by Christian Kindahl )
* DOWNLOAD C# Code für diese Lektion. ( Conversion by Brian Holley )
* DOWNLOAD Code Warrior 5.3 Code für diese Lektion. ( Conversion by Scott Lupton )
* DOWNLOAD Cygwin Code für diese Lektion. ( Conversion by Stephan Ferraro )
* DOWNLOAD D Language Code für diese Lektion. ( Conversion by Familia Pineda Garcia )
* DOWNLOAD Delphi Code für diese Lektion. ( Conversion by Michal Tucek )
* DOWNLOAD Dev C++ Code für diese Lektion. ( Conversion by Dan )
* DOWNLOAD Euphoria Code für diese Lektion. ( Conversion by Evan Marshall )
* DOWNLOAD Game GLUT Code für diese Lektion. ( Conversion by Milikas Anastasios )
* DOWNLOAD GLUT Code für diese Lektion. ( Conversion by Andy Restad )
* DOWNLOAD Irix Code für diese Lektion. ( Conversion by Lakmal Gunasekara )
* DOWNLOAD Java Code für diese Lektion. ( Conversion by Jeff Kirby )
* DOWNLOAD Jedi-SDL Code für diese Lektion. ( Conversion by Dominique Louis )
* DOWNLOAD JoGL Code für diese Lektion. ( Conversion by Pepijn Van Eeckhoudt )
* DOWNLOAD LCC Win32 Code für diese Lektion. ( Conversion by Robert Wishlaw )
* DOWNLOAD Linux Code für diese Lektion. ( Conversion by Richard Campbell )
* DOWNLOAD Linux/GLX Code für diese Lektion. ( Conversion by Mihael Vrbanec )
* DOWNLOAD Linux/SDL Code für diese Lektion. ( Conversion by Ti Leggett )
* DOWNLOAD LWJGL Code für diese Lektion. ( Conversion by Mark Bernard )
* DOWNLOAD Mac OS Code für diese Lektion. ( Conversion by Anthony Parker )
* DOWNLOAD Mac OS X/Cocoa Code für diese Lektion. ( Conversion by Bryan Blackburn )
* DOWNLOAD MASM Code für diese Lektion. ( Conversion by Nico (Scalp) )
* DOWNLOAD Visual C++ / OpenIL Code für diese Lektion. ( Conversion by Denton Woods )
* DOWNLOAD Power Basic Code für diese Lektion. ( Conversion by Angus Law )
* DOWNLOAD Pelles C Code für diese Lektion. ( Conversion by Pelle Orinius )
* DOWNLOAD Python Code für diese Lektion. ( Conversion by Ryan Showalter )
* DOWNLOAD Scheme Code für diese Lektion. ( Conversion by Brendan Burns )
* DOWNLOAD Solaris Code für diese Lektion. ( Conversion by Lakmal Gunasekara )
* DOWNLOAD Visual Basic Code für diese Lektion. ( Conversion by Peter De Tagyos )
* DOWNLOAD Visual Fortran Code für diese Lektion. ( Conversion by Jean-Philippe Perois )
* DOWNLOAD Visual Studio .NET Code für diese Lektion. ( Conversion by Grant James )



Deutsche Übersetzung: Joachim Rohde
Der original Text ist hier zu finden.
Die original OpenGL Tutorials stammen von NeHe's Seite.