21 Texture Mapping
21.010 Was sind die Grundlagen, um Texturen nutzen zu können ?
Als Minimum sind eine Texture Map anzulegen (Bild, Datenfeld etc.), der Textur-Modus
zu aktivieren und für jedes Vertex passende Texturkoordinaten festzulegen.
Damit ist es bereits möglich, ein texturiertes Objekt darzustellen. Obwohl noch
nicht alle der folgenden Schritte vor OpenGL 1.2 zur Verfügung stehen, kann man sich
an folgender Vorgehensweise orientieren.:
-
Für jede Textur ein Texture Object definieren,
// bestimmte Funktionen lassen sich durch Extensions simulieren
#if !defined(GL_VERSION_1_1) && !defined(GL_VERSION_1_2)
#define glBindTexture glBindTextureEXT
#endif
Ein mittels glBindTexture erzeugtes Texture Object enthält die Textur an sich
und alle speziellen Parameter für diese Textur (siehe auch Frage 21.070).
-
Eine Textur wird meist als MipMap (also in verschiedenen Auflösungen) gespeichert. Für die Berechnung
der MipMaps sowie der Parameterfestlegung stehen die Befehle
glTexParameterf, glTexEnvi und gluBuild2DMipmaps zur Verfügung.
-
Ist der Texturspeicher des Systems begrenzt, kann man die Prioritäten des Ladens/Entladens
der Texturen mittels glPrioritizeTextures() beeinflussen.
-
Die meisten Eigenschaften der Texture Objects lassen sich schon beim Laden der Textur, also
unabhängig vom Zeichnen festlegen. In der Zeichenfunktion selbst wird vor dem
zu texturierenden Objekt nur noch der Textur-Modus und das Texture Object aktiviert und nach dem
Fertigstellen des Objekts wieder deaktiviert.
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureID);
// Objekt zeichnen
// glDisable(GL_TEXTURE_2D);
21.020 Ich habe versucht mit Texturen zu arbeiten, aber nix geht. Warum ?
Man sollte zunächst das folgende überprüfen:
-
Der Textur-Modus und eine Textur (z.B. mit glTexImage2D oder als Texture Object)
muss aktiviert sein.
-
Die möglichen Parameter sind relativ komplex, eventuell ist hier eine ungünstige
Einstellung gesetzt worden.
-
Texture Objects speichern nicht alle Parameter (z.B. nicht die Angaben zu glTexGen).
-
Wird ein MipMap Filter (z.B. mittels glTexParameter* und einer MIN_FILTER oder MAG_FILTER Variable) festgelegt,
müssen auch alle Auflösungen der Textur berechnet worden sein (manuell oder mittels gluBuild2DMipmaps).
Alle Auflösungsstufen der Textur müssen auch die gleiche Anzahl an Komponenten (RGB, RGBA) haben.
-
OpenGL arbeitet als Status-Maschine, was auch heisst, dass die Texturkoordinaten explizit
anzugeben sind (manuell mit glTexCoord* oder automatisch mit glTexGen). Vergisst man das,
wird die letzte Texturkoordinate für alle nachfolgenden Vertices genutzt, was kaum
ein brauchbares Ergebnis liefern wird.
-
Verwendet man mehrere Contexts und will bestimmte Texture Objects gemeinsam nutzen, muss das
Texture Sharing aktiviert sein (wglShareLists bzw. glXCreateContext).
-
Lässt sich die Ursache so nicht abstellen, kann man auch auf glGetError() zurückgreifen.
21.030 Warum arbeitet die Beleuchtung nicht, wenn ich gleichzeitig Texturen nutze ?
Es gibt viele (gut gemeinte) Textur-Demos im Internet, die als Umgebungsvariable
GL_DECAL oder GL_REPLACE nutzen. Bei dieser Einstellung ersetzt die Textur aber
immer die darunterliegende Farbe des Objekts. Da die Beleuchtung nur die Farbwerte beeinflusst,
also vor dem Aufbringen der Textur abgeschlossen ist, erscheint das so texturierte Objekt
wie unbeleuchtet.
Die Standardeinstellung ist GL_MODULATE. Hier wird die Farbe des Objekts mit der Textur
vermischt, durch eintreffendes Licht erhellte Stellen erscheinen also auch mit Textur heller.
GL_MODULATE wird von den meisten OpenGL Programmen verwendet, wenn Texturen und Licht
benötigt werden.
glTexEnv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); /* nicht GL_DECAL oder GL_REPLACE */
21.040 Beleuchtung und Texturen arbeiten, allerdings bekomme ich das Specular
Highlighting nicht hin. Was ist los ?
Angenommen, euer Programm nutzt ein strahlend weisses Punktlicht. Dieses arbeitet wunschgemäss,
solange keine Textur auf das Objekt gelegt ist. Verwendet man nun eine rote Textur (1,0,0) und
GL_MODULATE, wird die endgültige Farbe (komponentenweise Rot*Weiss = 1,0,0 * 1,1,1 = 1,0,0) auch
nur Rot sein können, also ist das weisse Punktlicht nicht erkennbar.
Ab OpenGL 1.2 gibt es allerdings auch die Möglichkeit, derartige Punktlichter erst nach dem
Aufbringen der Textur zu berechnen:
glLightModel (GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR);
Standardmässig ist die Einstellung GL_SINGLE_COLOR, so dass die Ergebnisse auch
den früheren Standards von OpenGL entsprechen.
Aber auch ohne OpenGL 1.2 gibt es noch weitere Lösungen (z.B. Extensions).
Dieses Beispiel arbeitet z.B. auf HP Systemen, kann in Verbindung mit der
EXT_separate_specular_color Extension
aber auch für andere Systeme angepasst werden.
Nur auf Grundlage der OpenGL 1.0 Spezifikation arbeitet die folgende Idee:
Wenn man das Objekt zweimal zeichnet, einmal mit Licht und Textur, ein zweites mal nur
mit dem Punktlicht. Diese Lösung findet man auch im oben genannten
Beispiel wieder.
21.050 Wie kann ich die Texturkoordinaten automatisch berechnen lassen ?
Hierfür gibt es die glTexGen() Funktion.
21.060 Sollte ich Texturen in einer Display Liste speichern ?
Diese Frage wurde bereits bei den Display-Listen
beantwortet.
21.070 Wie arbeiten Textur-Objekte ?
Textur-Objekte speichern die Textur sowie alle hierfür angegebenen Einstellungen. Der Aufruf
kann dann mit einem einfachen glBindTexture() erfolgen.
Diese Funktion steht allerdings erst seit OpenGL 1.1 zur Verfügung, wurde aber bei
einigen Implementationen (z.B. SGI/IRIX) auch schon durch Extensions bereitgestellt, meist in
Zusammenhang mit Display-Listen.
Im Vergleich zur OpenGL 1.0 Lösung (über glTexImage*) sind Texture Objects
deutlich schneller.
Texture Objects lassen sich weitgehend mit Display-Listen vergleichen: Die eindeutige Bezeichnung
erfolgt mittels ID's (GLuint), die auch automatisch vergeben werden können (glGenTextures).
Ebenso lassen sich Texture Objects in verschiedenen Contexts gemeinsam nutzen.
Ein wichtiger Unterschied ist aber, dass sich Texture Objects jederzeit ändern lassen (Parameter und Bild).
Folgende Funktionen steuern ein Texture Object: glTexImage*(), glTexSubImage*(),
glCopyTexImage*(), glCopyTexSubImage*(), glTexParameter*(), glPrioritizeTextures()
und die gluBuild*Mipmaps* Funktionen.
Dagegen arbeiten glTexEnv*() und glTexGen*() unabhängig.
Texture Objects werden meist wie folgt angelegt:
-
Festlegen einer ID für jedes Texture Object, manuell oder mittels glGenTextures().
-
Aktivieren eines Texture Objects mit glBindTexture(). Jetzt können das Bild sowie
die Einstellungen festgelegt werden. Jedes Texture Objects muss einzeln angelegt werden.
-
Unmittelbar vorm Zeichnen eines Objekts kann nun ein derartig vorbereitetes Texture Object
mittels glBindTexture(ID) aktiviert werden.
21.080 Kann ich Texturen in verschiedenen Contexts nutzen ?
Ja, wenn man Texture Objects verwendet. Dann geht es genauso wie mit Display-Listen.
Die Funktionen wglShareLists() bzw. glXCreateContext() müssen nur mit entsprechenden
Parametern aufgerufen werden.
21.090 Wie kann ich mehrere Texturen auf eine Oberfläche aufbringen ?
Hierfür gibt es die ARB_multitexture Extension (EXT_multitexture und SGIS_multitexture
sollten nach Möglichkeit nicht mehr verwendet werden).
Die Spezifikation dieser Extension findet man hier
im Bereich OpenGL 1.2.1. Beispiele gibt es auf
Michael Gold's web page und in den
SIGGRAPH Kursen. Den dazugehörigen
Quellcode gibt es auf der
Advanced99 FTP site.
21.100 Wie kann ich Light Mapping realisieren ?
Man kann die Ausleuchtung einer Szene nicht nur mit echten Lichtquellen, sondern auch durch entsprechende
Texturen nachbilden. GLUT 3.7 enthält ein Beispiel (progs/advanced97/lightmap.c) für
diese Technik.
21.110 Wie kann ich meine Grafiken (gif, jpg, bmp) als Texturen nutzen ?
Nicht mit Funktionen der OpenGL.
Für das Einlesen von Bilddateien kann man prinzipiell jedes Verfahren (selbst gebastelt oder
Bibliotheken aus dem Netz) verwenden. Diese Bilddaten werden dann an glTexImage2D übergeben
und lassen sich dann wie jede andere Textur verwenden.
Beispiele findet man u.a. für TGA Dateien),
JPEG oder PNG
bzw. auch in diesem Abschnitt der FAQ.
21.120 Wie kann ich in eine Textur hinein zeichnen ?
Ab OpenGL 1.1 gibt es die Befehle glCopyTexImage2D() oder glCopyTexSubImage2D()
für diesen Zweck. Beide Funktionen lesen den aktuellen Framebuffer aus und nutzen
den Inhalt als aktuelle Textur. GLUT enthält ein Beispiel namens multispheremap.c.
21.130 Was ist die grösste Texturauflösung, die meine Grafikkarte
noch hardwarebeschleunigt ?
Eine gute OpenGL Implementation wird alle Hardwareunterstützung nutzen, die zur
Verfügung steht. Allerdings steht die tatsächliche Umsetzung frei.
Die OpenGL Spec sieht auch keinen Mechanismus vor, eine Hardwarebeschleunigung zu fordern oder
den aktuellen Weg abzufragen. Mit diesen Informationen im Hinterkopf kann allerdings
folgendes nützlich sein:
Mit folgendem Befehl erhält man die grösste unterstützte Textur:
GLint texSize;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texSize);
Diese Texturgrösse (GL_MAX_TEXTURE_SIZE) muss auch dann richtig dargestellt werden, auch wenn keine
Hardwareunterstützung zur Verfügung steht.
Man kann mit glGet*() allerdings nicht direkt auf die genutzten Parameter
(format, internalformat, type) der Textur zurückgreifen.
Ab OpenGL 1.1 gibt es allerdings einen sogenannten Texture Proxy, der wie folgt genutzt
werden kann:
glTexImage2D(GL_PROXY_TEXTURE_2D, level, internalFormat, width, height, border, format, type, NULL);
Der letzte Parameter pixels ist NULL, da OpenGL die Texturdaten im Falle
des Proxy nicht lädt. OpenGL überprüft nur die Ladbarkeit einer
Textur in der angegebenen Grösse. Ist das nicht möglich, werden Höhe und Breite
auf Null gesetzt. Das Ergebnis lässt sich dann wie folgt abfragen:
GLint width;
glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
if (width==0) {
/* Textur nicht nutzbar */
}
21.140 Wie kann ich eine Textur auf Kugeln, Zylindern oder anderen Objekten,
die mehrere Oberflächen haben, aufbringen ?
Die Texturkoordinaten müssen entsprechend berechnet und aufgeteilt werden, so dass
die Gesamttextur gleichmässig auf das Objekt verteilt wird.
|