Jenseits des Horizonts

Im Juli 2002 hat das OpenGL Architecture Review Board die Spezifikation von OpenGL 1.4 verabschiedet. Wie für jede Version gibt es auch für diese eine Reihe von Erweiterungen, die Qualität oder Geschwindigkeit der Bibliothek für 3D-Grafik verbessern.

vorlesen Druckansicht 7 Kommentare lesen
Lesezeit: 6 Min.
Von
  • Christian Marten
Inhaltsverzeichnis

Für die Weiterentwicklung von OpenGL ist das Architecture Review Board (ARB) verantwortlich, dem zurzeit dreizehn Firmen angehören. Das Gremium verabschiedete in bislang unregelmäßigen Abständen neue Versionen der Grafikbibliothek, welche die Portabilität von Anwendungen sicherstellen sollen. Jeder neue Standard ist abwärtskompatibel und erweitert OpenGL um neue Funktionen. Die Spezifikationen sind im Internet frei zugänglich (siehe ‘Online-Quellen’).

Online-Quellen
OpenGL:
Spezifikationen der Versionen www.opengl.org/developers/documentation/specs.html
Verzeichnis der Erweiterungen oss.sgi.com/projects/ogl-sample/registry/
glFont students.cs.byu.edu/~bfish/glfont.php
Extention Headers oss.sgi.com/projects/ogl-sample/ABI/glext.h www.ati.com/developer/sdk/RadeonSDK/Html/Info/Extensions/glATI.h
Utility Toolkit www.opengl.org/developers/documentation/glut/index.html?GLUT
Herstellerseiten:
Nvidia developer.nvidia.com/view.asp?IO=nvidia_opengl_specs
ATI mirror.ati.com/developer/proginfo.html#OpenGL
Apple developer.apple.com/opengl/extensions.html#GL_EXT_texture_filter_anisotropic

Erweiterungen über die OpenGL-Standards hinaus sind ein Segen und ein Fluch zugleich. Einerseits ermöglichen sie Schnittstellen zur Nutzung spezieller Hardware-Features wie Bewegttexturen aus Videoquellen, Singlepass Multitexturing und Pixelshader, andererseits erschwert ihr Einsatz die Portierung von OpenGL-Programmen auf verschiedene Plattformen. Erweiterungen setzen grundsätzlich auf einer wohl definierten Version der Bibliothek auf und legen zusätzliche Funktionen sowie neue Parameter für existente Funktionen fest. Ihre Spezifikationen sind ebenfalls im Internet einsehbar.

Zur Freude der Entwicklergemeinde gibt es eine ganze Reihe von Erweiterungen, über die unter den Herstellern breites Einvernehmen herrscht. Die Erweiterungen mit dem Präfix GL_ARB sind von allen Mitgliedern des ARB bestätigt und genießen die weiteste Verbreitung. Daneben existieren solche, die immerhin mehrere Hersteller befürworten (GL_EXT), sowie herstellerspezifische (GL_SGI, GL_NV etc.), was aber nicht bedeutet, dass andere Hersteller diese nicht ebenfalls unterstützen.

Die folgenden Ausführungen erläutern die Verwendung von Erweiterungen am Beispiel von GL_EXT_texture_filter_anisotropic, einer einfach zu verwendenden Extention, die OpenGL um einen anisotropischen Texturfilter bereichert, der die Tiefenperspektive einer Szene berücksichtigt. Dabei setzt der Text grundlegende Kenntnisse der Programmierung mit OpenGL voraus. Eine Einführung bietet das dreiteilige iX-Tutorial [1].

Als Texturfilterung bezeichnet man die Abtastung einer Texturfunktion an den Pixeln des zu texturierenden Polygons. Einfacher ausgedrückt legt das Filter fest, auf welche Weise die Abbildung der Texel einer Textur auf die Pixel eines Polygons erfolgt. Diese Aufgabe ist komplizierter, als es auf den Blick scheint. Form und Größe des Polygons unterscheiden sich bedingt durch die Projektion aus dem dreidimensionalen Raum auf die zweidimensionale Bildschirmebene in der Regel deutlich von den Maßen der Textur. Das hat zur Folge, dass es viele verschiedene, sinnvolle Möglichkeiten gibt, die Farbe eines Pixels aus den infrage kommenden Texeln zu berechnen.

Der OpenGL-Standard unterstützt lediglich einfache bilineare und trilineare Texturfilter. Diese liefern akzeptable Ergebnisse, sofern die Seitenverhältnisse des Polygons ungefähr denen der auf ihm anzubringenden Textur entsprechen. Sobald sich jedoch die horizontale Sampling-Rate der Textur deutlich von der vertikalen Rate unterscheidet, kommt es zu Unschärfen in der Abbildung. Bei Polygonen, die sich weit in die Tiefe einer Szene erstrecken - zum Beispiel Landebahnen in Flugsimulatoren -, mindert isotropische (richtungsunabhängige) Texturfilterung die Bildqualität beträchtlich.

Links: Ausgabefenster des Beispielprogramms mit trilinearer, anisotropischer Filterung (Abb. 1).

Anisotropische Filter tragen dem Rechnung, indem sie unterschiedliche Sampling-Raten für die Filterung in X- beziehungsweise Y-Richtung verwenden. Die Erweiterung GL_EXT_texture_filter_anisotropic spezifiziert die Schnittstelle zu einem solchen Filter für zweidimensionale Texturen, ohne die konkrete Implementierung für diesen vorzugeben. Sie ermöglicht es, jedem Texturobjekt einen bestimmten Grad an Anisotropie zuzuweisen, zusätzlich zur Angabe der Parameter der Standardfilter. Die API kommt mit der Definition zusätzlicher Konstanten aus, die sie altbekannten OpenGL-Funktionen wie glTexParameterf() oder glGetFloatv() übergibt.

Das Beispielprogramm zu den folgenden Ausführungen demonstriert die praktische Anwendung des anisotropischen Filters. Es ist unter Linux und Win32 getestet und setzt OpenGL Version 1.2, das OpenGL Utility Toolkit glut sowie die Erweiterung GL_EXT_texture_filter_anisotropic voraus. Aktuelle Treiber vieler Hersteller (zum Beispiel Nvidia, ATI, Apple) erfüllen diese Voraussetzungen. Zusätzliche Auskünfte geben die Herstellerseiten im Internet (siehe ‘Online-Quellen’).

Mehr Infos

Listing 1: anisotropic.cpp - gekürzte Fassung

1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <GL/glut.h>
5 extern "C" {
6 # include "glfont.h"
7 }
8
9 #ifndef GL_EXT_texture_filter_anisotropic
10 # error GL_EXT_texture_filter_anisotropic not supported on this
11 # system - sorry.
12 #endif
13
14 GLFONT fnt_antiqua20bf;
15 float zk=0.0;
16 float max_anisotropy;
17 float anisotropy = 1.0;
18 int filter[] = { GL_NEAREST, GL_LINEAR,
19 GL_NEAREST_MIPMAP_NEAREST,
20 GL_NEAREST_MIPMAP_LINEAR,
21 GL_LINEAR_MIPMAP_NEAREST,
22 GL_LINEAR_MIPMAP_LINEAR
23 };
24 char filterstr[][26] = { "GL_NEAREST",
25 "GL_LINEAR",
26 "GL_NEAREST_MIPMAP_NEAREST",
27 "GL_NEAREST_MIPMAP_LINEAR",
28 "GL_LINEAR_MIPMAP_NEAREST",
29 "GL_LINEAR_MIPMAP_LINEAR"
30 };
31
32 int minFilter=5;
33 int magFilter=1;
34 char text[][35] = {"Erweiterungen des OpenGL Standards",
35 "sind Segen und Fluch zugleich. ",
36 // ...
37 ""};
38
39 static void Init(void)
40 {
41 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy);
42
43 glEnable(GL_DEPTH_TEST);
44 glEnable(GL_BLEND);
45 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
46 filter[minFilter]);
47 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
48 filter[magFilter]);
49 glFontCreateASCII (&fnt_antiqua20bf, "antiqua_20_bf.fnt", 1, TRUE,
50 filter[minFilter], filter[magFilter]);
51 }
52
53
54 static void OnReshape(int width, int height)
55 {
56 // Viewport und Projection Matrix setzen
57 // ...
58 }
59
60 static void OnKey(unsigned char key, int x, int y)
61 {
62 switch (key) {
63 case 'q':
64 exit(0);
65 case 'a':
66 if (anisotropy==1.0)
67 anisotropy=max_anisotropy;
68 else
69 anisotropy=1.0;
70
71 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
72 anisotropy);
73 break;
74 case '-':
75 minFilter = (minFilter +1) %6;
76 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
77 filter[minFilter]);
78 break;
79 case '+':
80 magFilter = (magFilter +1) %2;
81 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
82 filter[magFilter]);
83 default:
84 break;
85 }
86 glutPostRedisplay();
87 }
88
89 static void OnDisplay(void)
90 {
91 short ln =0;
92 char lnBuffer[80];
93
94 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
95 glLoadIdentity ();
96 glScalef (0.4, 0.4 , 0.4);
97
98 // Hier Ausgabe des Status
99 // ...
100
101 // Hier setzen der ModelView Transformation
102 // ...
103
104 // Nun erfolgt Ausgabe des Lauftextes
105 glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
106 glEnable (GL_BLEND);
107 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
108
109 glFontBegin (&fnt_antiqua20bf);
110 while (text[ln][0]) {
111 glFontTextOut (text[ln], 0, 3-2.8*(float)ln,0);
112 ln++;
113 }
114 glFontEnd ();
115
116 glutSwapBuffers();
117 }
118
119 void OnIdle ()
120 {
121 zk += 0.05;
122 if (zk>100)
123 zk=0.0;
124
125 OnDisplay();
126 }
127
128 int main(int argc, char **argv)
129 {
130 char *s;
131
132 // OpenGL/GLUT Initialisierung, Registrierung der Eventhandler
133 // ...
134
135
136 s = (char *)glGetString (GL_EXTENSIONS);
137 if (strstr (s, "GL_EXT_texture_filter_anisotropic")==NULL) {
138 fprintf (stderr, "Sorry, your OpenGL library
139 does not support the necessary extention.\n");
140 exit (1);
141 }
142 glutMainLoop();
143
144 }

Tools wie glinfo der Suse-Linux-Distribution oder glxinfo unter Red Hat Linux geben Aufschluss darüber, welche Erweiterungen die installierte Bibliothek unterstützt. Ein ähnliches Programm für die Eingabeaufforderung von Microsoft Windows 9x/NT (glhinv.exe) ist zusammen mit dem Quellcode über den iX-Listingsservice verfügbar.

Die Präprozessordirektive #ifndef GL_EXT_texture_filter_anisotropic (Zeile 9) stellt sicher, dass die Übersetzung des Codes mit einer Fehlermeldung auf Systemen abbricht, deren OpenGL-Bibliothek nicht die notwendige Erweiterung bietet. Analog sorgt die main()-Funktion mittels glGetString(GL_EXTENSIONS) (Zeile 136) dafür, dass das Programm mit einer Fehlermeldung terminiert, sofern der ausführende Host keine anisotropischen Filter unterstützt. Ernsthafte Programme implementieren an den entsprechenden Stellen einen alternativen Code, der zumindest einen eingeschränkten Funktionsumfang bietet.

Rechts: Filterung entsprechend dem (isotropischen) Standard - sowohl das Minification- als auch das Magnification-Filter sind auf GL_NEAREST gesetzt (Abb. 2).

Je nach Tastatureingabe schaltet die Funktion OnKey() (Zeile 60) die Filtermodi um. Da die Zeichensatztextur in verschiedenen Auflösungen gespeichert als Mipmap vorliegt, kann der Anwender zwischen sechs Minification- und zwei Magnification-Filtern wählen. Für jede dieser Filterkombinationen lässt sich der Anisotropieparameter zwischen 1.0 (isotropische Filterung) und dem implementierungsspezifischen Maximum umschalten.

Die Textausgabe ist mit Hilfe einer Textur realisiert. Das Programm glFont von Brad Fish erzeugt aus einem Windows-Zeichensatz eine Textur und speichert diese zusammen mit Texturkoordinaten für jedes enthaltene Zeichen in einer .glf-Datei. Der Anwender kann dabei den Font sowie das Intervall der aufzunehmenden Zeichen frei wählen.

OpenGL-Programme nutzen für das Rendering die Funktion glFontTextOut() (Zeile 111) der glFont-API, um für jedes Zeichen eines Strings ein Rechteck mit dem passenden Bereich der Zeichensatztextur zu erzeugen. Die Rechtecke unterliegen dabei der Modelview-Transformation, sodass auch perspektivische Ansichten auf einen Text realisierbar sind.

glFontTextOut() verwendet die in der glf-Datei gespeicherten Texturkoordinaten, um einzelne Zeichen innerhalb der Textur zu adressieren. Da die Textur nur einmal zu Beginn der Textausgabe mittels glFontBegin() (Zeile 109) gebunden werden muss, ist das Verfahren sehr schnell.

Die vom Beispielprogramm verwendete Variante von glFont unterscheidet sich vom Original insofern, als sie mit einer ASCII-Darstellung der Font-Datei arbeitet. Dies hat den Vorteil, dass das Dateiformat unabhängig von der Fließkommadarstellung eines bestimmten Prozessortyps ist.

Christian Marten
arbeitet als Systems Engineer im Bereich Presales bei SGI Deutschland in Hannover.

[1] Christian Marten; OpenGL-Tutorial, Teil 1 bis 3; iX 12/1999, 1/2000, 2/2000 (ka)