Texelgenaue Texturkoordinate: Unterschied zwischen den Versionen
(GL_NEAREST als Option in der Zusammenfassung hinzugefügt) |
(Zusammenfassungstext + korrigierte Aussage bei Mipmap für GL_NEARESt) |
||
(Eine dazwischenliegende Version von einem anderen Benutzer wird nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
− | [[Texelgenaue Texturkoordinate|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. | + | [[Texelgenaue Texturkoordinate|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 = | = Anwendungsgebiet = | ||
Zeile 57: | Zeile 57: | ||
== Zusammenfassung == | == Zusammenfassung == | ||
+ | |||
+ | Wir stellen fest, dass alle Methoden ihre Vor- und Nachteile haben. Es gibt keine Pauschallösung für das Problem, wenn man nicht alle Bilder in separate Texturen packen will. Man muss sich also klar werden, welche Kriterien wichtig sind und dann die Methodik danach auswählen. Dazu sollte folgende Tabelle hilfreich sein: | ||
{|{{Prettytable_B1}} width="100%" | {|{{Prettytable_B1}} width="100%" | ||
Zeile 68: | Zeile 70: | ||
|✔ | |✔ | ||
|✔ | |✔ | ||
− | | | + | |✘ |
|✘ | |✘ | ||
|- | |- |
Aktuelle Version vom 27. Mai 2014, 19:17 Uhr
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.
Inhaltsverzeichnis
Anwendungsgebiet
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
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).
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
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
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
Wir stellen fest, dass alle Methoden ihre Vor- und Nachteile haben. Es gibt keine Pauschallösung für das Problem, wenn man nicht alle Bilder in separate Texturen packen will. Man muss sich also klar werden, welche Kriterien wichtig sind und dann die Methodik danach auswählen. Dazu sollte folgende Tabelle hilfreich sein:
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 | ✔ | ✔ | ✘ | ✔ |