Home
Über JOGL
  Entstehung
  Eigenschaften
  Installation
Tutorial
  Lektion1
  Lektion2
  Lektion3
  Lektion4
  Lektion5 
JOGL vs.
   OpenGL

Links
Impressum

 

 Lektion 5

Texturen verwenden
Texturkoordinaten
Texturen in der Beispielszene

Zum Download des Quellcodes dieser Lektion: Auf das Bild klicken oder hier.

Texturen verwenden

Durch die Verwendung von Texturen lässt sich eine Szene interessanter gestalten. Texturen sind Bilder, die auf Oberflächen angebracht werden, um diesen ein natürlicheres Aussehen zu geben.
In JOGL gibt es die Möglichkeit 1D-, 2D- und 3D-Texturen zu verwenden. Allerdings wird hier nur auf 2D-Texturen eingegangen werden, da diese am meisten genutzt werden.

Leider stellt JOGL keine Methode zur Verfügung, um Bilddateien einlesen zu können. Deshalb müssen solche Methoden entweder selbst geschrieben werden, oder man greift auf bereits vorhandene Implementierungen zurück. Eine gute Quelle hierfür ist die Seite von Nehe Productions (http://nehe.gamedev.net), auf der die Codebeispiele vielfach auch in JOGL implementiert zur Verfügung stehen.

Wenn Texturen verwendet werden sollen, müssen diese erst mit glEnable(..) aktiviert werden. Im Fall von 2D-Texturen wird glEnable(..) mit der Konstanten GL.GL_TEXTURE_2D aufgerufen. Um Texturen zu deaktivieren wird glDisable(..) verwendet.

Um eine 2D-Textur zu erzeugen, Wird der Befehl glTexImage2D(..) benötigt. Diesem werden neun Parameter übergeben. Der erste Parameter ist eine Integerkonstante. Diese wird bei der Erzeugung von 2D-Texturen auf GL.GL_TEXTURE_2D gesetzt.

Der nächste Parameter ist nur dann von Bedeutung, wenn für unterschiedliche Abstände zwischen Betrachter und betrachtetem Objekt verschiedene Detaillierungsgrade zur Verfügung gestellt werden sollen (Stichwort Mipmaps). Standardmässig sollte für diesen Parameter “0“ angegeben werden. Danach wird die Anzahl der Farbkomponenten in der Textur spezifiziert. Die wichtigsten Konstanten sind GL.GL_RGB, GL.GL_RGBA, GL.GL_ALPHA, GL.GL_LUMINANCE, GL.GL_LUMINANCE_ALPHA, GL.GL_INTENSITY.

Die nächsten zwei Parameter definieren die Breite und die Höhe der Textur. Breite bzw. Höhe müssen eine Potenz zur Basis 2 sein. Danach wird angegeben, ob ein Rahmen für die Textur verwendet werden soll (1) oder nicht (0).

Die nächsten beiden Parameter geben Format und Datentyp des Arrays an, in dem die Bilddaten gespeichert sind. Als Werte für Format kommen z.B. GL.GL_RGB oder GL.GL_RGBA in Frage, während der Typ beispielsweise durch GL.GL_BYTE oder GL.GL_INT übergeben werden kann. Das Array, das die Bilddaten für die Textur enthält, wird durch den letzten Parameter übergeben.

Wenn mehrere Texturen angelegt werden sollen, kommen Texturobjekte zum Einsatz, an die die Texturen gebunden werden. Diese Objekte werden dann im Arbeitsspeicher abgelegt von wo aus sie beliebig oft geladen werden können. Dies beschleunigt den Vorgang erheblich, da ein erneutes Einlesen der Texturen entfällt.

Um Texturobjekte zu erzeugen, müssen zuerst Objektnamen in einem Integerarray bereitgestellt werden. Dies geschieht in der Methode glGenTextures(..). Dieser wird zuerst die Anzahl der bereitgestellten Namen übergeben, dann das Integerarray. Nach dem Methodenaufruf existieren jedoch noch keine Texturobjekte. Im zweiten Schritt wird deshalb glBindTexture(..) aufgerufen. Dieser Methode wird die Art der Textur, bei 2D GL.GL_TEXTURE_2D, und der Name des Texturobjekts übergeben.

nach oben

Texturkoordinaten

Bei der Erstellung von Texturen muss zudem auf die Berechnung der Texturkoordinaten geachtet werden. Da zwischen den Koordinaten der Textur und den Koordinaten der Szene (Vertexkoordinaten) unterschieden wird, müssen die Texturkoordinaten an die Vertexkoordinaten angepasst werden.

Texturkoordinaten haben vier Komponenten, die als s-, t-, r- und q-Koordinate bezeichnet werden. Diese entsprechen den bekannten x-, y-, z- und w-Koordinaten. Für 2D-Texturen sind daher nur s und t von Bedeutung; q wird im Allgemeinen der Wert 1 zugeordnet und bei der Erzeugung von homogenen Koordinaten benötigt.

In JOGL lassen sich Texturkoordinaten automatisch berechnen. Dies geschieht mit den Methoden glTexGeni(..) und glTexGenfv(..). In glTexGeni(..) wird der Modus festgelegt, nach dem die Texturkoordinaten berechnet werden. Als erster Parameter wird die Texturkoordinate angegeben, die berechnet werden soll, also entweder GL.GL_S,GL.GL_T, GL.GL_R oder GL.GL_Q.

Der zweite Parameter ist die Konstante GL.GL_TEXTURE_GEN_MODE. Dies ist der Generierungsmodus. Als letzter Parameter wird mittels einer Konstante übergeben, mit welcher Funktion die Texturkoordinaten berechnet werden sollen.

Wenn GL.GL_OBJECT_LINEAR angegeben wird, werden die Texturkoordinaten als Linearkombination einer Ebene mit den geometrischen Koordinaten erzeugt. Wenn (p1, p2, p3, p4) die übergebene Ebene und (x, y, z, w) die Objektkoordinaten des Vertex darstellen, dann berechnet sich die Texturkoordinate wie folgt [Ker02]:
generierte Texturkoordinate = p1x + p2y + p3z + p4w
Wird GL.GL_EYE_LINEAR gewählt, dann bewirkt dies ebenfalls eine lineare Gewichtung, allerdings in eye-Koordinaten [Ker02]:
generierte Texturkoordinate = p'1x + p'2y + p'3z + p'4w
wobei (p'1, p'2, p'3, p'4) = (p1, p2, p3, p4) M-1

Eine dritte Möglichkeit ist GL.GL_SPHERE_MAP. Diese bewirkt sphärisches Mapping bezüglich der Parameter s und t. Hierzu werden keine weiteren Angaben benötigt, da sich die Texturkoordinaten allein auf der Basis der geometrischen Koordinaten berechnen. Außerdem werden Normalenvektoren und der Blickpunkt berücksichtigt, um einen "Rundumblick" bezüglich des Objekts zu erzeugen. Dies erscheint dann so, als ob die Umgebung auf der Oberfläche gespiegelt werden würde.

Danach werden mit der Methode glTexGenfv(..) die Werte für (p1, p2, p3, p4) übergeben. Als erster Parameter wird wieder die Konstante übergeben, die für die zu berechnende Texturkoordinate steht, also entweder GL.GL_S, GL.GL_T, GL.GL_R oder GL.GL_Q. Danach wird wiederum der Name der Generierungsmodus für die Texturkoordinaten angegeben. Als symbolische Namen können hierbei GL.GL_TEXTURE_GEN_MODE, GL.GL_OBJECT_PLANE oder GL.GL_EYE_PLANE übergeben werden.

Der letzte Parameter gibt das Array an, in dem sich die Koeffizienten für die Generierung der Texturkoordinaten befinden. Wurde als Generierungsmodus GL.GL_TEXTURE_GEN_MODE gewählt, dann muß dieses Array eine einzige symbolische Konstante enthalten und zwar entweder GL.GL_OBJECT_LINEAR, GL.GL_EYE_LINEAR oder GL.GL_SPHERE_MAP. Ansonsten wird ein Array mit den vier Werten (p1, p2, p3, p4) übergeben.

Schließlich muss noch die Berechnung der Koordinaten eingeschaltet werden. Dies geschieht mit glEnable(..), wobei je nach Bedarf GL.GL_TEXTURE_GEN_S, GL.GL_TEXTURE_GEN_T, GL.GL_TEXTURE_GEN_R oder GL.GL_TEXTURE_GEN_Q als symbolische Konstante übergeben wird.

Oft kann es vorkommen, dass eine Textur auf einen Bereich gezeichnet wird, dessen Ausmaße größer oder kleiner sind als die der Textur. Deshalb ist es sinnvoll, festzulegen, auf welche Art und Weise die Textur vergrößert oder verkleinert werden soll, so dass sie in den Bereich der angegebenen Pixel passt. Diese Verfahrensweise gehört in den Bereich des Filterings und die Einstellungen bezüglich der Vergrößerung (magnification) bzw. der Verkleinerung (minification) geschehen über den Befehl gl.glTexParameteri(..). Diesem Befehl wird zuerst die Dimension der Textur übergeben, dann eine der beiden symbolischen Konstanten GL.GL_TEXTURE_MIN_FILTER (minification) bzw. GL.GL_TEXTURE_MAX_FILTER (magnification).

Als letzter Parameter wird die Einstellung für das Filtering angegeben, d.h. die Methode, mit der bestimmt wird, in welcher Farbe die Pixel gezeichnet werden sollen. Mit GL.GL_NEAREST wird dem Pixel die Farbe des Texels gegeben, dessen Mittelpunkt dem Mittelpunkt des Pixels am nächsten liegt. Mit der Einstellung GL.GL_LINEAR wird eine Mittelung der vier nächstgelegenen Farbwerte bewirkt.
Abschließend sei erwähnt, dass bei der Verwendung von glu-Primitiven mit der Methode glu.gluQuadricTexture(..) die Texturkoordinaten erstellt werden. Dieser Methode wird das Quadrics-Objekt und true übergeben, wenn die Koordinaten erstellt werden sollen.

nach oben

Texturen in der Beispielszene

Nun wollen wir Texturen verwenden um das Spielfeld realistischer zu gestalten. Nachdem wir eine Textur mit den Maßen 512x512 Pixeln mit Photoshop erzeugt haben, soll diese geladen und auf das Spielfeld angebracht werden. Die Methoden makeRGBTexture(..) und readPNGImage(..) stammen aus der Lesson06 von der Nehe Productions Seite [Dul04].

Wir haben dabei die Erzeugung der Textur in die Methode defineTexture(..) ausgelagert, die einmal in der init-Methode aufgerufen wird:

private int texture;
public void defineTexture(GL gl,GLU glu)
{
    gl.glShadeModel(GL.GL_SMOOTH);

    gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);

    //Texturobjekt erstellen
    texture = TextureGenerator.genTexture(gl);
    gl.glBindTexture(GL.GL_TEXTURE_2D, texture);

    //Erzeugen der Textur
    BufferedImage img = TextureGenerator.readPNGImag ("spielfeld2.png");

    TextureGenerator.makeRGBTexture(gl, glu, img,
    GL.GL_TEXTURE_2D, false);

    //Einstellen der Filtering-Komponenten
    gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER,     GL.GL_LINEAR);
    gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER,     GL.GL_LINEAR);

    //wir wollen, dass die Textur das aktuell verwendete Material
    //ersetzt
    gl.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE);
}

Die Methode drawField(..) wird ebenfalls abgeändert:

public void drawField(GL gl, GLU glu)
{
    gl.glEnable(GL.GL_TEXTURE_2D);
    gl.glBindTexture(GL.GL_TEXTURE_2D, texture);

    gl.glBegin(GL.GL_QUADS);
        gl.glTexCoord2f(0f, 0f);
        gl.glVertex3f(-6.5f, -1.5f, -6.5f);

        gl.glTexCoord2f(1f, 0f);
        gl.glVertex3f(-6.5f, -1.5f, 6.5f);

        gl.glTexCoord2f(1f, 1f);
        gl.glVertex3f(6.5f, -1.5f, 6.5f);

        gl.glTexCoord2f(0f, 1f);
        gl.glVertex3f(6.5f, -1.5f, -6.5f);
    gl.glEnd();

    gl.glDisable(GL.GL_TEXTURE_2D);
}

nach oben