Tutorial TexFilter

Aus DGL Wiki
Wechseln zu: Navigation, Suche

Texturen-Feintuning

Einführung

Hi, eigentlich wollte ich ja nur ein Sample über Texture Compression schreiben. Als ich Phobeus davon erzählt habe, hat er mir nahegelgt, doch gleich ein ganzes Tutorial über Texture Filter, etc. zu schreiben. Ich hab mich dazu breitschlagen lassen*g*. Es lässt sich nicht ganz umgehen, dass ich hier ein paar Basics zu den Tapeten wiederholen muss, aber ich denke das könnt ihr verkraften.

Texturen filtern

Filtern? Ein etwas ungewöhlicher Ausdruck für 3D Grafik. Kaffe kann man filtern, aber Texturen? Texturen sind gewöhnlich Quadrate oder Rechtecke. Wird ein Polygon, über das eine Textur geklebt ist, auf dem Bildschirm angezeigt, so entsprechen oft mehrere Texel einem Pixel(Minification) oder nur Teile eines Texels einem Pixel(Magnification):

Tutorial TexFilter magmin.gif

Für Beide Fälle stehen zwei Filtermethoden zur Verfügung:

GL_NEAREST

Einem Pixel wird genau das Texel zugewiesen, dass dem Zentrum des Pixels am nächsten liegt. Dies führt häufig zu Bildschirmartefakten, ist aber die schnellere der beiden Varianten.

GL_LINEAR

Dem Pixel wird der Durchschnitt eines 2x2 Arrays von Texeln, die dem Zentrum des Pixels am nächsten liegen, zugewiesen. Dies führt zu einem weicheren Ergebnis, ist aber auf den meisten OpenGL Geräten langsamer.

Wie wird nun aber ein Filter auf eine Textur angewendet? Nachdem eine Textur mit glBindTexture ausgewählt wurde, werden ihr mittels glTextParameteri die unterschiedlichen Filter zugewisen:

    glBindTexture(GL_TEXTURE_2D, DemoTexture);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

Das Beispielt wählt für die DemoTextur den MAGnification Filter nearest und für den MINification Filter linear.

Filterergebnisse einer 8x8 Schachbrettextur(links: linear, rechts: nearest):

Tutorial TexFilter 8x8checkerlinear.gif
Tutorial TexFilter 8x8checkernearest.gif
GL_LINEAR GL_NEAREST

Filterergebnisse einer bunten Textur

Tutorial TexFilter colored.gif
Tutorial TexFilter coloredlinear.gif
Tutorial TexFilter colorednearest.gif
Ausgangstextur GL_LINEAR GL_NEAREST

Mipmapping

Mipmaps sind eine Art Level of Detail für Texturen. Die Seitenlänge der Originaltextur wird halbiert und dann als eigenes Bild im Speicher abgelegt. Das gleiche geschieht mit dem halbiertem Bild, bis nur noch eine Textur der größe 1x1 übrig bleibt. Wird nun eine Textur in großer Entfernung angezeigt, wird von der Textur eine kleinere Version gewählt, als wenn die Textur nur wenig Abstand zur Kamera hat. Dadurch kann die Bildqualität erheblich verbessert werden.

Zum erstellen der Mipmaps kommt in OpenGL meist gluBuild2DMipmaps zum Einsatz. Wird DevIL verwendet, hilft einem diese Funktion meist wenig(bei Texture Compression zeige ich wies trotzdem geht), besonders wenn Paletten zum Einsatz kommen. Hier gibt es die Funktion ilutGLBuildMipmaps. Beispielsweise ließen sich mit folgender Funktion Texturen laden:

function LoadDevILTexture(Filename : String): TGLUInt;
var
  id:TILInt;
begin
  {$T-}
  // Laden eines Texture in den Speicher
  ilGenImages(1, @id);
  ilBindImage(id);
  ilLoadImage(PChar(Filename));

  // Übergeben der Texture an OpenGL
  Result := ilutGLBindMipmaps;
  glBindTexture(GL_TEXTURE_2D, Result);
  {Hier könnten die Filteroptionen stehen}

  // Da OpenGL die Texture hat, können wir sie aus dem Speicher entfernen
  ilDeleteImages(1, @Id);
  {$T+}
end;

Achtung:DevIL muss vor dem erstmaligem Aufruf noch initialisiert werden:

ilInit;
ilutRenderer(IL_OPENGL);

Nun stehen für den Minification Filter folgende neue Funktionen zur Verfügung: GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_NEAREST und GL_LINEAR_MIPMAP_LINEAR. Ergebnisse in genau dieser Reihenfolge, wobei der Magnification Filter bei allen auf nearest gesetzt ist:

Tutorial TexFilter nearestmipmapnearest.gif
Tutorial TexFilter nearestmipmaplinear.gif
GL_NEAREST_MIPMAP_NEAREST GL_NEAREST_MIPMAP_LINEAR
Tutorial TexFilter linearmipmapnearest.gif
Tutorial TexFilter linearmipmaplinear.gif
GL_LINEAR_MIPMAP_NEAREST GL_LINEAR_MIPMAP_LINEAR

Texture Compression

Hinter Texture Compression versteckt sich etwas sehr interessantes. Um Grafiken für das Web benutzen zu können, werden sie häufig komprimiert(z.B. JPEG), damit sie weniger Platz beanspruchen. Das Gleiche gibt es Unter OpenGl. Hier steht schließlich nicht unendlich viel Platz im Grafikkartenspeicher zur Verfügung. Wenn man also auch hier die Texturen komprimiert, dann kann man wesentlich mehr Texturen unterbringen. Nebenbei wird die Sache auch noch schneller, da beim Zugriff auf die Textur weniger Daten über den Bus laufen müssen. Möglich wird Texture Compression unter OpenGL durch eine Extension namens GL_ARB_TEXTURE_COMPRESSION. Um herauszufinden ob diese Extension vorliegt, müssen wir OpenGL12 anweisen, alle Extensions auszulesen:

ClearExtensions;
ReadExtensions;

Gewöhlich geschieht dies nach dem setzten des Pixelformats, etc. aber noch vor dem Laden irgendwelcher Texturen. Ist jetzt GL_ARB_texture_compression auf true gesetzt, können wir Texturkompression verwenden. Wenn an OpenGL die Texturdaten mittels glTexImage2D die Bilddaten übergeben werden, muss nun einfach als internalformat nicht GL_RGB angegeben werden, sondern GL_COMPRESSED_RGB_ARB. Klingt sehr simpel... Für DevIL müssen wir uns noch etwas spezielles einfallen lassen, denn wenn die Daten mithilfe einer Palette dargestellt werden bringen sie wenig. Sie müssen vorher konvertiert werden:

    function LoadDevILTextureCompressed(Filename : String): TGLUInt;
    var
      id:TILInt;
      imageInfo : TILInfo;
      Data : PILUByte;
      compressed : Integer;
    begin
      if not GL_ARB_texture_compression then
        LoadDevILTexture(Filename);
      {$T-}
      // Laden einer Texture in den Speicher
      ilGenImages(1, @id);
      ilBindImage(id);
      ilLoadImage(PChar(Filename));  // Loads into the current bound image

      //Wir brauchen das Bild als IL_RGB oder IL_RGBA
      ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE);

      // Übergeben der Texture an OpenGL
      iluGetImageInfo(@ImageInfo);
      Data := ilGetData();

      glGenTextures(1, @Result);
      glBindTexture(GL_TEXTURE_2D, Result);

      //einfache textur
      glTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_ARB,
                        ImageInfo.Width, ImageInfo.Height, 0,
                        GL_RGB, GL_UNSIGNED_BYTE, Data);
      //oder für mipmaps:
      //gluBuild2DMipmaps(GL_TEXTURE_2D,
      //         GL_COMPRESSED_RGB_ARB,
      //         ImageInfo.Width, ImageInfo.Height,
      //         GL_RGBA, GL_UNSIGNED_BYTE, Data);

      glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_ARB, @compressed);
      if compressed <> 1 then
        MessageDlg('Texture wurde nicht komprimiert', mtError, [mbOk], 0);


      {Filteroptionen}

      ilDeleteImages(1, @Id);
      {$T+}
    end;

IL_RGB und GL_RGB können bei bedarf durch IL_RGBA und GL_RGBA ausgetauscht werden. Werden Mipmaps benötigt, so muss einfach vor gluBuild2DMipmaps die Kommentare gelöscht werden. Dem geübten Auge werden sicherlich die komprimierten Schmankerl auffallen, bewegt sich aber die Szenerie sehr schnell, wird es niemandem mehr auffallen:

Tutorial TexFilter compressed.gif

Euer

Delphic

Vorhergehendes Tutorial:
Tutorial Objektselektion
Nächstes Tutorial:
Tutorial Kamera1

Schreibt was ihr zu diesem Tutorial denkt ins Feedbackforum von DelphiGL.com.
Lob, Verbesserungsvorschläge, Hinweise und Tutorialwünsche sind stets willkommen.