Texelgenaue Texturkoordinate

Aus DGL Wiki
Version vom 27. Mai 2014, 14:15 Uhr von Lord horazont (Diskussion | Beiträge) (GL_NEAREST als Option in der Zusammenfassung hinzugefügt)

Wechseln zu: Navigation, Suche

Texelgenaue Texturkoordinaten werden immer dann gebraucht, wenn man mehrere Bilder in einer Textur hat, z.B. bei einer Tilemap oder wenn man zur Laufzeit einen dynamischen Texturatlas erzeugt.

Anwendungsgebiet

Beispiel eines Texturatlas. Unterschiedliche Texturen sind in einem Bild untergebracht.

Ein häufiges Anwendungsgebiet ist wie schon erwähnt das Addressieren von Texturen in einem Texturatlas. Dazu muss man Pixelgenau die einzelnen Teilbilder herausschneiden, um sie auf Objekten anzubringen.

Wenn der Ausschnitt die Pixel im Rechteck x0..x1, y0..y1 abdeckt, dann ist die intuitive Methode um die Texturkoordinaten u0,u1,v0,v1 für eine Textur der Breite w und Höhe h zu erhalten:

 u0 = x0 / w
 u1 = x1 / w
 v0 = y0 / h
 v1 = y1 / h

Beispiel

Um das zweite Tile von links in der untersten Zeile auszuwählen, müssen wir das Rechteck mit x0=64, x1=128, y0=192, y1=256 aus der Textur mit w=256, h=256 rausschneiden. Damit erhalten wir:

 u0 = x0 / w = 0.2500
 u1 = x1 / w = 0.5000
 v0 = y0 / h = 0.7500
 v1 = y1 / h = 1.0000

Problematik

Info DGL.png Die Problematik tritt nicht auf, wenn man GL_NEAREST verwendet. In dem Fall reicht es, die obige Methode zur Berechnung der Texturkoordinaten zu verwenden.

Diese Koordinaten bergen allerdings Probleme in sich, sobald man einen anderen Texturfilter als GL_NEAREST verwendet und die Texel nicht 1:1 auf Pixel übertragen werden (also irgendeine Form der Skalierung der Textur statt findet).

Ein Tile mit den obigen Texturkoordinaten auf ein 4×4 größeres Quad gezeichnet
Dann kommt es zu bleeding-Effekten, bei denen die nebenanliegenden Texturen in das gewollte Bild reinblenden. In dem Beispiel oben wurde das zweite Tile von links ganz unten (64 px×64 px) auf ein Quad welches mit 256 px×256 px gerendert wurde mit GL_LINEAR aufgebracht. Man kann deutlich erkennen wie die nebenanliegenden Tiles in das Tile hineinbleeden.

Lösung 1: Texturaddressierung verändern

Tile welches mit den links stehenden Koordinaten auf ein gleich großes Quad gezeichnet wurde (Screenshot um Faktor 2×2 interpolationsfrei hochskaliert)
Eine Lösung für dies, die oft genannt wird, ist, den Rahmen der Texturaddressierung in die mitte der Texel zu legen. Dazu addiert bzw. subtrahiert man von den Texturkoordinaten einen halben Texel:

 u0 = (x0 + 0.5) / w
 u1 = (x1 - 0.5) / w
 v0 = (y0 + 0.5) / h
 v1 = (y1 - 0.5) / h

Dann liegen die Ränder des angezeigten Quads genau auf der Texelmitte, es findet also keine Überblendung mit nebenanliegenden Tiles statt. Dieser Ansatz hat allerdings ein anderes Problem: Die Texturen verschwimmen schon bei einer 1:1 Abbildung, wie im Screenshot rechts zu sehen.

Lösung 2: Rahmen hinzufügen

Tile mit Rahmen, welches mit den originalen Texturkoordinaten auf ein 4×4 größeres Quad gezeichnet wurde
Man kann den bleeding-Effekt auch beheben, indem man einen 1 px Rahmen um die Texturen im Atlas hinzufügt, welcher die Farbe des anliegenden Texturpixels hat (und in den Ecken eventuell eine lineare Überblendung). Obiges Bild demonstriert, dass dies das Problem löst.

Allerdings hilft diese Lösung nicht, wenn man (automatisch generierte) Mipmaps verwendet. Dafür muss man den Rahmen für jedes Mipmap-Level verdoppeln, was ab einem gewissen Mipmap-Level zu viel Platz benötigt. Oft ist es allerdings so, dass man, wenn man Mipmaps braucht (also unterschiedliche Skalierungen einer Textur anzeigen will) sowieso keine pixelgenaue Darstellung benötigt.

Ein weiterer Nachteil ist, dass man N×M+4 Pixel verschwendet, von denen nur die Hälfte verwendet werden.

Zusammenfassung

Technik / Kriterium Kein bleeding Pixelgenaue Darstellung bei 1:1 Rendering Mipmap-Kompatibilität Lineares Filtering bei Zoom
Normal mit GL_NEAREST
Normal mit GL_LINEAR (ggfs. + Mipmap)
Lösung 1: Ausschnitt verkleinern
Lösung 2: Rahmen hinzufügen