OpenGL.org 3Dsource.de: Infos rund um 3D-Computergrafik, OpenGL und VRML
space Telefon-Tarife space VDI - Arbeitskreis Fahrzeugtechnik space Beschallungsanlagen und Elektroakustik space Heise-News space

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.

Seite durchsuchen nach:

Fragen oder Ideen an:
Thomas.Kern@3Dsource.de
Linux-Counter
(C) Thomas Kern