![]() ![]() ![]() |
|
![]() |
|
![]() |
![]() ![]() ![]() ![]() ![]() ![]() |
Texture Filtering bezeichnet den Vorgang, bei dem die Darstellung einer Textur im dreidimensionalen Raum auf die zweidimensionale Bildschirmfläche übertragen wird. Nach einem bestimmten Filtersystem werden die Bildschirmpixel aus den Texturpixeln errechnet. Die verschiedenen Filter werden wir in diesem Kapitel genauer kennenlernen.
Wenn Sie sich schon mal mit der Bildbearbeitung (in 2D) beschäftigt haben, werden Sie die Problematik, um die es hier geht, bereits kennen. Angenommen, wir haben ein 256x256 grosses Bild. Wird dieses Bild auf einer Fläche dargestellt, die auch 256x256 Pixel gross ist, sehen wir das Bild originalgetreu im normalen Zustand. Wenn wir dieses Bild aber auf einer 300x300 Pixel grossen Fläche darstellen würden, müssten sich mehrere Bildschirmpixel auf die gleichen Texturpixel beziehen. Doch nach welchen Regeln werden die Bildschirmpixel aus den Texturpixeln errechnet? Problematisch wird es auch, wenn wir das Bild auf einer wesentlich kleineren Fläche darstellen würden. Dann können unter Umständen einige Texturpixel gar nicht berücksichtigt werden. Das Bild könnte verzerrt wirken.
Bei der Transformierung von 3D nach 2D passiert genau das gleiche: eine Textur wird in unterschiedlichen Grössenverhältnissen dargestellt, je nachdem, wie nah oder weit der Betrachter vom Polygon entfernt ist. Zur Darstellung der Textur gibt es verschiedene Filter, die sich sowohl auf die Bildqualität als auch auf die Geschwindigkeit in der Anwendung auswirken können.
Um die verschiedenen Technik deutlicher aufzeigen zu können, gehen wir anhand eines Beispieles vor. Die Textur, die Sie auf der linken Seite sehen, werden wir nun den verschiedenen Filtertechniken unterziehen und sehen, was passiert.
Dies ist die älteste und schnellste Methode, Texel in Bildschirmpunkte zu verwandeln. Dabei wird errechnet, zu welchem Texel der Bildschirmpunkt am nächsten liegt. Die Farbe des Texels wird dann ohne zusätzliche Berechnungen direkt übernommen. Das Resultat sieht in der 3D-Awendung dann so aus:
Durch die direkte Zuweisung der Texel kommt es zu einer leicht verzerrten Darstellung des Bildes. So ist zum Beispiel die obere waagerechte Linie dicker als die untere. In der diagonalen grünen Linie sind nicht alle Kästchen gleich dick. Diese Fehler entstehen, weil die berechneten Koordinaten auf ganzzahlige Werte gerundet werden.
Diese Filtertechnik ist sinnvoll, wenn Sie ganz bewusst eine Textur zeigen möchten, bei der jeder einzelne Pixel des Bildes erkennbar ist. Der Performancegewinn bei diesem Filter ist sehr gering, da sich die meisten Grafikkarten auf den folgenden Filter spezialisiert haben.
Beim linearen Filter berechnet DirectX Mittelwerte aus den Texel. Liegt zum Beispiel ein Bildschirmpixel genau zwischen zwei Texel, werden die Farben der beiden Texel zu einer Durchschnittsfarbe gemischt, und diese dann angezeigt. Unsere Textur sieht dann so aus:
Nur damit keine Missverständnisse entstehen: der Rahmen des Bildes ist nur der Hintergrund der 3D-Anwendung, die ich dafür geschrieben habe. Er gehört nicht mit zur Textur. Bei der Darstellung der Textur fällt auf, dass diese leicht verschwommen wirkt. Das ist sozusagen der Preis den man dafür zahlt, dass die Verhältnisse der einzelnen Linien nun wirklich stimmen. Sowohl die waagerechten Linien wirken gleich dickt, als auch die Diagonale, bei der man die einzelnen Pixel nur noch erahnen kann.
Das Anisotropic Filtering ist sozusagen der lineare Filter für die Tiefe. Solange Sie orthogonal auf eine Textur schauen, erhalten Sie mit dem linearen Filter die besten Ergebnisse. Wenn aber eine Textur auch in die tiefe des Raumes verläuft, kann es zu Verzerrungen kommen, da Texel, die sich in verschiedenen Distanzen vom Betrachter befinden aus Gründen der Perspektive nur unzureichend in die Berechnung mit aufgenommen werden. Während beim linearen Filter die Berechnungsfläche kreisförmig ist, haben wir beim anisotropischen Filter eher eine elliptische Berechungsfläche. Da meine Grafikkarte diesen Effekt nicht unterstützt musste ich notgedrungen auf ein Bild von der Internetseite TecChannel zurückgreifen.
Hier sehen wir einen direkten Vergleich zwischen dem Point Filter und dem Anisotropic Filter. Der entscheidende Unterschied ist: beim anisotropischen Filter werden selbst die Kästchen, die sich ganz weit im Hintergrund befinden, noch glaubwürdig angezeigt, während beim Point Filter alles in einem ungeordneten Pixelsalat endet, bevor die letzte Mipmap das Schachbrett ganz verschwommen anzeigt.
Wenn Sie noch nicht wissen, was Mipmaps sind, dann sollten Sie zuerst den entsprechenden Abschnitt im Theoriekapitel lesen.
Mipmaps werden von DirectXGraphics automatisch generiert. Das heisst, Sie müssen nicht extra seperate Texturen anlegen. Sie stellen DirectXGraphics lediglich die hochauflösendste Textur zur Verfügung. Das Programm erstellt dann von selbst die gewünschste Anzahl an Mipmaps. Dabei ist zu beachten, dass jede kleinere Mipmap genau die halbe Breite und Höhe der vorrausgehenden Auflösung hat. Sie sollten also von vornherein die Texturgrössen so wählen, dass Sie möglichst oft durch zwei teilbar sind. Am idealsten ist es, Grössen, wie 256x256 oder 128x128 zu nehmen. Aber auch Auflösungen, wie 256x64, sind denkbar. Wie Sie Mipmaps erstellen, erfahren Sie im Kapitel Texturen laden und anwenden.
Und so rechnet DirectXGrahics: wenn Sie bei einer Texturgrösse von 256x256 3 Miplevel erstellen, dann ist das erste Level 256x256, das zweite 128x128 und das dritte 64x64. Sie können nur so viele Mipmaps erstellen, bis die Texturgrösse 1x1 beträgt (in unserem Beispiel wären das also 9 Mipmaps). Ein Mipmaplevel kommt dann immer zum Einsatz, wenn die Auflösung der jeweiligen Mipmap in etwa gleich ist mit der Grösse der Textur auf dem Bildschirm. Bei unserer Beispieltextur kann das zum Beispiel so aussehen.
Hier sehen Sie gleich zwei Mipmaps im Bild. Der linke Teil der Textur ist noch soweit im Vordergrund, dass die hochauflösende Textur verwendet wird. Ab einem bestimmten Punkt wird aber eine Grenze überschritten, bei der die zweite kleinere Textur zum Einsazt kommt. Daher wirkt das Bild weiter links ein wenig verschwommen.
Auch für Mipmaps können Sie einstellen, was für Filter Sie verwenden möchten. Beim Point Filtering zum Beispiel sehen Sie diese scharfen Kanten, wie im Screenshot. Wählen Sie statt dessen Linear Filtering, dann werden auch hier wieder Mittelwerte bestimmt, diesmal zwischen den beiden Mipmaps die dem Pixel am nächsten liegen. Je nach Grafikkarte ist dann der Übergang nicht mehr erkennbar bzw. bei älteren Grafikkarten von leichtem Bildrauschen geprägt.
Sie können mit ein paar Faktoren noch die Übergangsabstände zwischen zwei Mipmaps beeinflussen. Zum einen erreichen Sie dies mit dem Texturestagestate D3DTSS_MIPMAPLODBIAS.
function F2DW(f: Single): DWORD; begin Result:= PDWord(@f)^; end; begin d3ddev8.SetTextureStageState( 0, D3DTSS_MIPMAPLODBIAS, f2dw(2.1)); |
Mit diesem Parameter stellen Sie ein, wie früh oder spät eine gering-auflösende Mipmap zum Einsatz kommt. Je grösser der Wert ist, desto schneller kommt eine Textur mit geringer Auflösung zum Einsatz. Je geringer (also kleiner als 0) der Wert ist, desto hochauflösender ist die Textur auch bei grösseren Distanzen. Da Float-Werte eigentlich nicht in der .SetTextureStageState-Funktion verwendet werden dürfen, muss man sich einer kleinen Funktion bedienen, die auf diesen Floatingwert zeigt.
Zum Schluss noch einen anderen Parameter: D3DTSS_MAXMIPLEVEL
d3ddev8.SetTextureStageState( 0, D3DTSS_MAXMIPLEVEL, 2 ); |
Mit diesem Parameter bestimmen Sie, ab welchem Miplevel die Textur angezeigt werden soll. Ist der Wert 0, so wird die Textur auch in ihrer höchsten Auflösung verwendet. Ist der Wert 1, so wird als bestauflösende Textur das erste Miplevel benutzt, usw. . Mit diesem Parameter können Sie also auch, nachdem Sie eine komplette Mipmapkette erstellt haben, noch entscheiden, wie hochauflösend die Textur aus der Nähe sein soll.
Die Texturfilter wählen Sie über die .SetTextureStageState-Funktion des Devices aus. Dabei wird unterschieden zwischen einem Filter, der angewendet wird, wenn die Textur auf einer grösseren Pixelfläche dargestellt werden soll, und einem Filter der bei einer kleineren Pixelfläche, als die der Textur, angewendet werden soll. Darüberhinaus können Sie noch einen Filter für den Einsatz von Mipmaps angeben. Der jeweilige Funktionsaufruf dafür sieht folgendermassen aus:
d3ddev8.SetTextureStageState( 0, D3DTSS_MAGFILTER, D3DTEXF_LINEAR ); d3ddev8.SetTextureStageState( 0, D3DTSS_MINFILTER, D3DTEXF_LINEAR ); d3ddev8.SetTextureStageState( 0, D3DTSS_MIPFILTER, D3DTEXF_POINT ); |
D3DTSS_MAGFILTER, D3DTSS_MINFILTER und D3DTSS_MIPFILTER sind dabei Konstanten aus den D3DTEXTURESTAGESTATETYPE-Flags. MAG steht für Maginification (Vergrösserung) und Min für Minification (Verkleinerung). Mit einem
D3DTEXTUREFILTERTYPE-Flag können sie dabei als dritten Paramter den genauen Filter auswählen.
Der aufwendigste Filter muss nicht immer der beste sein. Damit Sie besser erkennen können, welche Filter in welcher Kombination am besten zueinander passen, liegt der Dokumentation ein Texturfilterkasten bei. In diesem Programm können Sie zur Laufzeit die Filter und Mipmaps beliebig einstellen und direkt sehen, was passiert.
Das Programm lädt die bereits gezeigte Textur. Diese bewegt sich ständig vom Betrachter weg und zum Betrachter hin. Gleichzeitig rotiert sie um sich selbst. Damit können Sie die Übergänge zwischen zwei Mipmaps besser beobachten.