Getupfte Pixel

Nachdem die schwierigsten Hürden der OpenGL-Programmierung bereits in den beiden vorangegangenen Kursteilen genommen wurden, soll es im letzten Teil darum gehen, die Objekte der virtuellen Welt mit Oberflächenmustern zu versehen. Dazu kommt das Rendering transparenter Flächen mittels Alpha Blending.

In Pocket speichern vorlesen Druckansicht 5 Kommentare lesen
Lesezeit: 13 Min.
Von
  • Christian Marten
Inhaltsverzeichnis

Texturen sind zweidimensionale Bilder, die in einer Szene wie Plakate auf die Oberflächen der Objekte geklebt werden und ihnen so eine Struktur verleihen. Der Einsatz von Texturen erhöht nicht nur die Realitätsnähe einer Szene dramatisch, er sorgt in vielen Fällen auch für eine Verminderung der Komplexität der virtuellen Welt. So sind beispielsweise die gemauerten Wände des Titelbilds durch zwei Rechtecke realisiert, auf die das Bild einer Mauer als Textur aufgebracht ist. Aktuelle Grafikkarten berechnen Texturen in Hardware, sodass das Rendering texturierter Flächen nur unwesentlich langsamer ist als das solcher ohne Texturen. Eine Modellierung jedes einzelnen Steins wäre ungleich aufwändiger.

Gemessen an den Effekten, die sich mit Texturen erzielen lassen, sind die Grundlagen ihrer Programmierung mit OpenGL verblüffend einfach. OpenGL unterstützt diese Technik ausschließlich im RGB-Modus und verlangt grundsätzlich nach rechteckigen Texturen, deren Seitenlängen, in Pixeln gemessen, Zweierpotenzen sein müssen. Allerdings lassen sich beliebige polygonale Unterbereiche einer Textur ohne weiteres auf die 3D-Flächen kleben. Dabei ist es nicht erforderlich, dass das Texturpolygon genau auf die 3D-Fläche passt; OpenGL dehnt und zerrt es passend zurecht. Jede OpenGL-Implementierung unterstützt Texturen von mindestens 64 x 64 Texel (Texturpunkt) Größe.

Programme laden Texturdaten in der Regel aus Grafikdateien in den Hauptspeicher. Das OpenGL-Interface ist flexibel genug ausgelegt, um nahezu jedes unkomprimierte Dateiformat direkt verarbeiten zu können. Sind die Daten eingelesen, sollte eine Anwendung sie zusammen mit Rendering-Parametern über glTexImage2D (Listing 1, Zeile 55) in einem Texturobjekt speichern. Solche Objekte sind eine mit der Spezifikation 1.1 eingeführte Erweiterung, die es erlaubt, die entsprechenden Daten im lokalen Texture Memory des Grafiksubsystems zu speichern. Das erstmalige Anlegen von Texturobjekten erfolgt über die Funktion glGenTextures (Listing 1, Zeile 46), die ein Array mit Texturobjektnummern zurückgibt, unter denen Texturdaten samt Parametern abgelegt und später referenziert werden können. Ein bestimmtes Texturobjekt wird durch die Übergabe seiner Nummer an glBindTexture (Listing 1, Zeile 51) zum aktuellen Objekt. Alle folgenden Änderungen an Texturparametern (mit Ausnahme von Texturfunktionen, siehe unten) wirken sich auf dieses Objekt aus. Soll ein Primitiv mit einer bestimmten Oberflächenstruktur versehen werden, ist diese einfach vor dem Rendering des Primitivs über ihre Nummer wiederum mit glBindTexture zu selektieren. Texturobjekte können nach Gebrauch über glDeleteTextures (Listing 1, Zeile 59) gelöscht werden, um Speicherplatz für neue Texturen freizugeben.

Mehr Infos

Listing 1: Init

 1   static void Init(void)
2 {
3 static float light0_ambient[] = {0.4, 0.4, 0.4, 1.0};
4 static float light0_diffuse[] = {0.8, 0.8, 0.8, 1.0};
5 static float light0_pos[] = {1.0, 1.0, 1.0, 1.0};
6 static float lmodel_ambient[] = {0.0, 0.0, 0.0, 1.0};
7 static float mat_shininess[] = {8.0};
8 static float mat_specular[] = {1.0, 1.0, 1.0, 1.0};
9 short int i;
10 Texture_t *t;
11
12 /* Z-Buffer Test einschalten */
13 glEnable (GL_DEPTH_TEST);
14 /* gefuellte Polygone rendern */
15 glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
16 /* Farbe zum Loeschen des Framebuffers setzen*/
17 glClearColor (0.2, 0.1, 0.1, 1.0);
18 /* Gewichtsfaktoren f. Blending einstellen */
19 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
20 /* Bei aktiviertem Culling die Rueckseite nicht darstellen*/
21 glCullFace (GL_BACK);
22
23 /* Quadric f. Darstellung des Globussockels erzeugen */
24 quadric = gluNewQuadric ();
25 gluQuadricTexture (quadric, GL_TRUE);
26
27 /* --- Light Setup --- */
28
29 /* Lichtquelle 0 einstellen*/
30 glLightfv (GL_LIGHT0, GL_AMBIENT, light0_ambient);
31 glLightfv (GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
32 glLightfv (GL_LIGHT0, GL_POSITION,light0_pos);
33
34 /* Beleuchtungsmodell waehlen*/
35 glLightModelfv (GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
36 glLightModeli (GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
37 /* Materialeigenschaften definieren */
38 glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
39 glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
40
41 /* ...und Beleuchtung einschalten. */
42 glEnable (GL_LIGHTING);
43 glEnable (GL_LIGHT0);
44
45 /* --- Texture Setup --- */
46 glGenTextures (3, textures); // Platz f. 3 Texturobjekte anfordern...
47
48 for (i=0; i<NUM_TEXTURES; i++) {
49 printf ("Loading %s\n", texFileNames[i]);
50 /* Aktuelles Texturobjekt selektieren */
51 glBindTexture (GL_TEXTURE_2D, textures[i]);
52 /* Image laden.. */
53 t = LoadSGI (texFileNames[i]); /* "wood.rgb"); */
54 /* ...und Pixeldaten an das Texturobjekt uebergeben. */
55 glTexImage2D (GL_TEXTURE_2D, 0, t->format, t->width, t->height,
56 0, t->format, GL_UNSIGNED_BYTE, t->bmp);
57 /* OpenGL "merkt" sich die Image-Daten im Texturobjekt, sodass */
58 /* hier bereits der Hauptspeicher wieder freigegeben werden kann */
59 DeleteTexture (t); /* ruft in main glDeleteTextures auf */
60
61 /* Textur f. Koord. ausserhalb v. [0;1] zyklisch wiederholen (in S-
62 und T-Richtung */
63 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
64 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
65 /* Filtermodus f. Vergroesserung und Verkleinerung einstellen */
66 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
67 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
68 }
69
70 /* Per Default berechnete Pixelfarbe durch Texelfarbe ersetzen */
71 glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
72
73 /* ... und Texturemapping einschalten nicht vergessen...*/
74 glEnable (GL_TEXTURE_2D);
75 }

Das Aufkleben der Textur auf ein Primitiv erfolgt durch das Setzen einer 2D-Texturkoordinate mittels glTexCoord*() (Listing 2, Zeile 18) vor jedem Aufruf der Funktion glVertex*(), die die 3D-Eckpunkte der Fläche festlegt. Der so definierte Texturpunkt wird gewissermaßen am Eckpunkt der Fläche festgeheftet. Die linke untere Ecke der Textur hat die Koordinaten (0.0, 0.0), die rechte obere (1.0, 1.0). Vierdimensionale Vektoren, deren Komponenten mit s, t, r und q bezeichnet werden, spezifizieren Texturkoordinaten wie Punkte. Dieses Tutorial beschränkt sich auf die Angabe von s- und t-Koordinaten, die den gewohnten zweidimensionalen (x,y-)Koordinaten entsprechen.

Mehr Infos

Listing 2: Display

    1   static void Display(void)
2 {
3 static float mat_diffuse[] = {0.8, 0.8, 0.8, 0.2};
4
5 /* Altes Bild loeschen */
6 glClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
7
8 /* Modelview-Matrix initialisieren */
9 glLoadIdentity ();
10 /* View Transformation von gluLookAt berechnen lassen */
11 gluLookAt (0.0,0.9,3.6, 0.0,0.1,0.0, 0.0,1.0,0);
12
13 /* --- Tisch darstellen --- */
14 /* aktuelle Textur setzen und ...*/
15 glBindTexture (GL_TEXTURE_2D, textures[WOOD]);
16 /* ...Primitiv rendern. Die Texturkoordinaten nutzen GL_REPEAT.*/
17 glBegin (GL_QUADS);
18 glTexCoord2i (0, 0); glVertex3i (-2, -1, -2);
19 glTexCoord2i (0, 5); glVertex3i (-2, -1, 2);
20 glTexCoord2i (5, 5); glVertex3i ( 2, -1, 2);
21 glTexCoord2i (5, 0); glVertex3i ( 2, -1, -2);
22 glEnd ();
23
24 /* --- Globusstativ darstellen --- */
25 glRotatef (20,0,1,0);
26 /* Status der momentan aktivierte Features, Materialeigenschaften */
27 /* und Linieneinstellungen speichern */
28 glPushAttrib (GL_ENABLE_BIT | GL_LINE_BIT | GL_LIGHTING_BIT);
29 /* Texture-Mapping f. Rahmen und Achse deaktivieren */
30 glDisable (GL_TEXTURE_2D);
31 /* Material mit Alpha=0.2 setzen... */
32 glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
33 glPushMatrix ();
34 glRotatef (-60,0,0,1);
35 DrawTorus (0.04, 0.85, 10, 60, 180); /* Rahmen */
36 glLineWidth (2.0); /* Linienbreite=2 Pixel*/
37 glBegin (GL_LINES); /* Achse */
38 glVertex3f ( 0.85, 0.0, 0.0);
39 glVertex3f (-0.85, 0.0, 0.0);
40 glEnd();
41 glPopMatrix ();
42 /* Und alten Status wieder herstellen */
43 glPopAttrib ();
44
45 glPushMatrix ();
46 glTranslatef (0.0, -0.8, 0.0);
47 glRotatef (90,1,0,0);
48 glBindTexture (GL_TEXTURE_2D, textures[SOCLE]);
49 gluCylinder (quadric, 0.0, 0.6, 0.2, 20,1); /* Sockel rendern */
50 glPopMatrix ();
51
52 /* --- Globus darstellen --- */
53 glPushMatrix ();
54 glRotatef ( 30,0,0,1);
55 glRotatef (-90,1,0,0);
56 glRotatef (-angle*180.0 / M_PI,0,0,1);
57 glBindTexture (GL_TEXTURE_2D, textures[EARTH]);
58 DrawGlobe (0.8,40);
59 glPopMatrix ();
60
61 /* ...und BackBuffer in Frontbuffer kopieren */
62 glutSwapBuffers ();
63 }

Die meisten Rendering-Parameter für Texturen setzen die Funktionen glTexParameter* (Listing 1, Zeile 63) und glTexEnv* (Listing 1, Zeile 71). Liegen beispielsweise Texturkoordinaten außerhalb des Intervalls [0.0; 1.0], entscheidet ein Aufruf von glTexParameter* mit GL_TEXTURE_WRAP_S als Parameter, ob die gesamte Textur in s-Richtung wie ein Kachelmuster zyklisch wiederholt wird (GL_REPEAT) oder nur ihre Randspalten (GL_CLAMP). Gleiches gilt für die t-Richtung mit GL_TEXTURE_WRAP_T. Das Beispielprogramm nutzt den Kachelmechanismus für die Darstellung des Tisches.

Wenn die Textur an den Eckpunkten eines Primitivs befestigt ist, übernimmt OpenGL die Zuordnung aller übrigen Punkte der Fläche zu Texeln der Textur. Da die Textur im Allgemeinen nicht dieselbe Größe wie die 3D-Fläche hat, muss sie entweder vergrößert oder verkleinert werden. Dies hat zur Folge, dass ein Texel mehrere Pixel abdeckt oder anders herum ein Pixel auf mehrere Texel fällt. Der Parameter GL_TEXTURE_MAG_FILTER von glTexParameter* bestimmt, wie die Zuordnung von Texeln auf Pixel für eine Vergrößerung der Textur erfolgen soll. Der Wert GL_NEAREST bedeutet, dass dasjenige Texel zugeordnet wird, dessen Koordinate dem Zentrum des Pixels am nächsten liegt. GL_LINEAR hingegen weist OpenGL an, dem Pixel den gewichteten Mittelwert des am nächsten gelegenen 2x2-Texelquadrats zuzuweisen. Bei Texturverkleinerungen gilt Entsprechendes für den Parameter GL_TEXTURE_MIN_FILTER. sample4 wechselt zwischen beiden Filtermodi über die Taste <f> (Listing 3, Zeile 16).

Mehr Infos

Listing 3: Key

    1   /* Reaktionen auf Tastaturereignisse */
2 static void Key (unsigned char key, int x, int y)
3 {
4 short int i;
5
6 switch (key) {
7 case 27: /* Esc */
8 exit(1);
9 ...
10 case 'b':
11 /* Alpha Blending ein-/ausschalten */
12 doBlend = 1-doBlend;
13 if (doBlend) glEnable (GL_BLEND); else glDisable (GL_BLEND);
14 break;
15 ...
16 case 'f':
17 /* Filtermodus fuer Texturen wechseln */
18 if (texFilter==GL_LINEAR) texFilter=GL_NEAREST; else texFilter=GL_LINEAR;
19 for (i=0;i<NUM_TEXTURES;i++) {
20 glBindTexture (GL_TEXTURE_2D, textures[i]);
21 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, texFilter);
22 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, texFilter);
23 ...
24 default:
25 break;
26 }
27 glutPostRedisplay ();
28 }

Ausschnitte aus sample.4c veranschaulichen Textur- und Blending-Einstellungen.

Der Globus aus Beispielprogramm 4: Die Texturen sind in drei verschiedenen Modi aufgebracht: GL_REPLACE (oben), GL_MODULATE (mitte) und GL_BLEND (unten). Die Taste 'm' schaltet zwischen den Modi um, 't' aktiviert und deaktiviert die Texturen (Abb. 1 bis 3).

Nach der Zuordnung von Texeln auf Pixel kann der Programmierer noch über glTexEnv* zwischen vier Funktionen wählen, die Texel- und (durch Farb- oder Materialzuweisung berechnete) Pixelfarbe auf unterschiedliche Weise kombinieren. OpenGL berechnet die endgültige Pixelfarbe nach Formeln, die vom Datenformat der Textur und der gewählten Texturfunktion abhängen. Die Tabelle ‘Pixel- und Texelfarben’ fasst die für RGB- und RGBA-Texturen verwendeten Formeln zusammen. Im einfachsten Fall ersetzt die Texturfunktion GL_REPLACE einfach die Farbe des Pixels durch die des Texels. GL_MODULATE multipliziert die RGB-Werte jedes Pixels mit denen des korrelierenden Texels komponentenweise, sodass Beleuchtungseffekte zum Tragen kommen.

Die Funktionen zur Angabe von Farben und Materialeigenschaften im RGB/RGBA-Modus akzeptieren neben den Farbintensitäten für Rot, Grün und Blau einen so genannten Alphawert als vierten Parameter. Anschaulich entspricht die Alphakomponente eines Punktes seiner Transparenz. Ihr Wertebereich reicht wie der der Farbkomponenten von 0.0 (vollständig transparent) bis 1.0 (vollständig opak).

OpenGL berechnet bei aktiviertem Blending die (neue) Farbe eines Pixels als Linearkombination aus der (alten) Farbe des Pixels im Framebuffer (Zielpixel) und der Farbe des neu berechneten Pixels (Quellpixel). Beide Farben multipliziert das System mit Gewichtungsfaktoren und schreibt die Summe der beiden Produkte als neuen Farbwert in den Framebuffer zurück. Die Linearkombination berechnet es für jeden Farbkanal getrennt und mit eigenen Faktoren.

Pixel- und Texelfarben
Texturfunktion RGB-Textur RGBA-Textur
GL_REPLACE C = Ct
A = Ap
C = Ct
A = At
GL_MODULATE C = Cp * Ct
A = Ap
C = Cp * Ct
A = Ap * At
GL_DECAL C = Ct
A = Ap
C = Cp * (1 - At) + Ct * At
A = Ap
GL_BLEND C = Cp * (1 - Ct) + Cenv * Ct
A = Ap
C = Cp * (1 - Ct) + Cenv * Ct
A = AP * At
Kombinationsmöglichkeiten von Pixel- und Texelfarben für RGB- und RGBA-Texturen:
C bezeichnet Farbangaben, A Alphawerte. Die Indizes stehen für Pixel- (p) beziehungsweise Texeldaten (t).
Cenv ist ein über glTexEnv* gesetzer RGBA-Vektor.
Blending-Faktoren
Konstante anwendbar auf Blendfaktor
GL_ZERO Quelle + Ziel (0,0,0,0)
GL_ONE Quelle + Ziel (1,1,1,1)
GL_DST_COLOR Quelle (Rd, Gd, Bd, Ad)
GL_ONE_MINUS_DST_COLOR Quelle (1 - Rd, 1 - Gd,1 - Bd, 1 - Ad)
GL_SRC_COLOR Ziel (Rs, Gs, Bs, As)
GL_ONE_MINUS_SRC_COLOR Ziel (1 - Rs, 1 - Gs,1 - Bs, 1 - As)
GL_SRC_ALPHA Quelle + Ziel (As, As, As, As)
GL_ONE_MINUS_SRC_ALPHA Quelle + Ziel (1 - As,1 - As, 1 - As, 1 - As)
GL_DST_ALPHA Quelle + Ziel (Ad, Ad, Ad, Ad)
GL_ONE_MINUS_DST_ALPHA Quelle + Ziel (1 - Ad,1 - Ad, 1 - Ad, 1 - Ad)
GL_SRC_ALPHA_SATURATE Quelle (f,f,f,1) mit f = min (As, 1- Ad)
Mögliche Blending-Faktoren: R, G, B stehen für die Farbkanäle, A für den Alphakanal.
Die Indizes bezeichnen Quellpixel (s) und Zielpixel (d).

Der Schlüssel zu Blending-Effekten liegt in der Wahl der Gewichtungsfaktoren, die über glBlendFunc (Listing 1, Zeile 19) gesetzt werden. glBlendFunc erwartet zwei Parameter als Gewichte für Quell- und Zielpixel, die Werte aus der Tabelle ‘Blending-Faktoren’ annehmen können. Es ergibt sich eine Unzahl an Kombinationsmöglichkeiten, von denen aber längst nicht alle sinnvoll sind. Um beispielsweise eine gleichmäßige Überlagerung zweier Bilder zu zeichnen, erfolgt das Rendering des ersten Bildes mit GL_ONE als Quellpixelfaktor und GL_ZERO als Zielpixelfaktor. Anschließend setzt man über glBlendFunc (GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA) andere Gewichte für das zweite Bild, und das Rendering geschieht mit einem Alphawert von 0.5. Soll das zweite Bild nur zu 25 Prozent in die Überlagerung eingehen, wählt man einfach Alpha = 0.25.

Über die Taste 'b' aktiviert sample4 Alpha Blending. Die Weltkartentextur besitzt einen (binären) Alphakanal. Landpunkte haben einen Alphawert von 255, Wasserpunkte einen von 0, deshalb sind sie bei aktiviertem Alpha Blending vollständig transparent. Der Rahmen des Globus ist mit einem Alphawert von 0.2 teilweise transparent. Die Leertaste schaltet wie bisher zwischen Drahtgitter- und ausgefüllter Darstellung um, 'c' aktiviert beziehungsweise deaktiviert Backface Culling (Abb. 4 und 5).

Einige der Gewichtungsfaktoren (beispielsweise GL_DST_COLOR) erfordern die Existenz eines Alphakanals im Framebuffer, da sie Alphawerte der Zielpixel in die Berechnung einbeziehen. GLUT-Programme müssen diesen bei Einrichtung eines Rendering-Kontexts mittels glutInitDisplayMode durch Angabe von GLUT_RGBA an Stelle von GLUT_RGB anfordern.

Alphawerte lassen sich nicht nur in Farb- und Materialangaben spezifizieren, auch Texturen können einen Alphakanal besitzen, wie sample4 anhand des Globus demonstriert.

Die wohl häufigste Ursache für das Blending-Fehlverhalten eines Programms liegt in der Reihenfolge des Objekt-Rendering. Da OpenGL mit glBlendFunc eine flexible Schnittstelle zu den Blending-Funktionen bereitstellt, kommt es genau darauf an, welche Farbe sich bereits im Framebuffer befindet und welche es neu zeichnen soll. Auch die Berechnung verdeckter Flächen mittels Z-Buffer kann den Programmierer leicht ins Staunen versetzen. Da der Z-Buffer-Test vor der Blending-Operation erfolgt, findet letztere gar nicht erst statt, wenn ein bereits dargestellter Punkt den neu zu zeichnenden verdeckt.

OpenGLs Alphakanal eröffnet eine Vielzahl interessanter Anwendungen, die aufgrund ihrer Komplexität hier nur kurz vorgestellt, nicht aber beschrieben werden können (Details finden sich in [3]). So lässt sich beispielsweise der Blick auf eine Szene durch eine blaue Glasscheibe durch das Rendering eines bildschirmfüllenden Rechtecks mit der Farbangabe (0.0, 0.0, 1.0, 0.2) realisieren. Schatten kann der Programmierer implementieren, indem er eine geeignete Projektionsmatrix in die Modelview-Transformation einbaut und dafür sorgt, dass OpenGL ein zweites Rendering mit aktiviertem Alpha Blending in der Farbe des Schattens für die betroffenen Objekte vornimmt.

Ein Algorithmus zum Rendering teilweise transparenter Szenen macht das Zeichnen von Pixeln von ihren Alphawerten abhängig (Alphatest). In einem ersten Durchlauf erfolgt nur ein Rendering für Pixel mit einem Alphawert von 1.0. Der zweite berücksichtigt nur transparente Objekte mit einem Alphawert kleiner 1.0. Steht der Z-Buffer im zweiten Durchlauf auf ‘Read Only’, werden transparente Flächen korrekt dargestellt, unabhängig von der Reihenfolge ihres Rendering.

sample4.c veranschaulicht die besprochenen Textur- und Blending-Einstellungen. (Lauffähige Programme sind über den iX-Listingsservice erhältlich.) Der grobe Rahmen des Programms entstammt den Beispielen der vorangegangenen Kursteile. DrawTorus und DrawGlobe sind unspektakuläre Funktionen, die einen (Teil-)Ring beziehungsweise eine Kugel zeichnen, und allenfalls Mathematikerherzen höher schlagen lassen.

Die Init-Funktion (Listing 1) lädt drei Texturen und legt sie in Texturobjekten ab - die Weltkarte des Globus, seine Sockeltextur und die Holzmaserung des Tisches. Zum Speichern verwendet das Beispiel SGIs RGB-Format, da es im Gegensatz zu verbreiteten Formaten wie BMP, GIF oder JPG einen Alphakanal für Blending-Effekte unterstützt und eine vergleichsweise einfache Struktur aufweist. Für eigene Experimente lässt sich das Mini-Interface, bestehend aus LoadSGI() (Zeile 53) und DeleteTexture() (Zeile 59), problemlos ‘recyceln’. Tools wie XV, Showcase oder Gimp können Bitmaps vieler gängiger Formate in RGB konvertieren. Alternativ ist es möglich, fast jedes (nicht komprimierte) Grafikformat in den Speicher zu lesen und OpenGL direkt als Textur zu übergeben. Nähere Informationen hierzu bietet die Online-Hilfe unter glTexImage2D (Zeile 55) und glPixelStore*. Hier noch eine Warnung bezüglich des BMP-Formats: Die Farben Rot und Blau sind bei diesem Format gegenüber OpenGLs Erwartungen vertauscht. Man muss also manuell nachbessern oder auf die bei den meisten OpenGL-Implementierungen unter MS-Windows vorhandene GL_EXT_bgra-Erweiterung zurückgreifen.

Mit Hilfe von OnIdle ist die Drehung des Globus realisiert, die GLUT immer dann aufruft, wenn gerade nichts anderes zu tun ist. Sie setzt lediglich den Drehwinkel des Globus in Abhängigkeit von der verstrichenen Zeit. Die Existenz von OnIdle hat main GLUT über glutIdleFunc mitgeteilt.

Schließlich stellt die Display-Funktion (Listing 2) drei interessante Neuerungen vor. Mit gluLookAt (Zeile 11) nimmt die GLU-Bibliothek die Berechnung der View-Transformation vor. Parameter sind Positionsvektor, Fokus des Blicks und ein Vektor für die Definition von ‘oben’. Das Funktionspaar glPushAttrib (Zeile 28) und glPopAttrib (Zeile 43) sichert aktuelle Rendering-Parameter auf einem Stack beziehungsweise stellt die alten Werte wieder her. glBindTexture (Zeile 48) und glTexCoord* (Zeile 18) zeigen die alltägliche Arbeit mit Texturobjekten.

OpenGL bietet weit mehr Möglichkeiten, als dieser Kurs vermitteln kann, selbst wenn er zehn oder mehr Teile hätte. Für fotorealistische Darstellungen kommen fortgeschrittene Techniken wie Szenen-Antialiasing, Spiegelungen oder Schattenwurf zum Einsatz. Mit Texturen lassen sich deutlich mehr Dinge anstellen als das letzte Beispiel hat demonstrieren können. Gleiches gilt auch für die im zweiten Teil vorgestellten Beleuchtungseinstellungen. Farbige Lichtquellen generieren zusammen mit atmosphärischen Effekten wie Rauch und Nebel stimmungsvolle Szenen. Stetig gekrümmte Spline-Flächen anstelle klobiger Polygonnetze perfektionieren Objekte. In der konstruktiven Computergrafik ist die Auswahl und Manipulation der ‘gerenderten’ Objekte einer Szene grundlegend. OpenGL unterstützt dies durch Mechanismen wie Selection und Feedback.

Zu Gunsten der Übersichtlichkeit sind Performance-Aspekte in den Beispielen weitgehend unberücksichtigt geblieben. OpenGL ist dank seiner Beschränkung auf konvexe, planare Polygone sowie durch Features wie Display Lists, Backface Culling oder Vertex Arrays eine extrem schnelle API für zwei- und dreidimensionale Grafikausgabe.

Als weiterführende Lektüre zu diesen Themen sei das Standardwerk von Mason Woo, Jackie Neider und Tom Davis, oft auch ‘The Red Book’ genannt [3], empfohlen.

Christian Marten
arbeitet bei GE CompuNet in Hannover als System-Ingenieur.

[1] James Foley, Andries van Dam, Steven Feiner, John Hughes, Richard L. Phillips; Grundlagen der Computergraphik; Einführung, Konzepte, Methoden; Addison-Wesley, Bonn 1994

[2] Renate Kempf, Chris Frazier; OpenGL Reference Guide; Addison-Wesley, Reading 1997

[3] Mason Woo, Jackie Neider, Tom Davis; OpenGL Programming Guide; Addison-Wesley, Reading 1997

[4] Internetseite der OpenGL Open Community

[5] Internetseite; Homepage der Mesa-Bibliothek

Mehr Infos

iX-TRACT

  • Das Anbringen zweidimensionaler Bilder auf der Oberfläche eines Objekts lässt eine Szene deutlich realistischer erscheinen.
  • OpenGL unterstützt solche Texturen ausschließlich im RGB-Modus und verlangt ein rechteckiges Format.
  • Bei der Berechnung von Farben und Materialeigenschaften berücksichtigt OpenGL neben den Farbintensitäten von Rot, Grün und Blau einen Alphawert, der die Transparenz angibt.
  • Seit der OpenGL-Spezifikation 1.1 lassen sich Texturen als Objekte im dafür vorgesehenen lokalen Speicher des Grafiksubsystems ablegen.

Tutorial Teil 1: Schnelle Pixel (ka)