• Keine Ergebnisse gefunden

Kontakt und Updates

2.5 Das erste Dreieck

2.6.1 Was Texturen sind

2.6.1.1 Der Zweck einer Textur

Texturen – diesen Begriff hat wahrscheinlich jeder schon einmal gehört, auch dann, wenn er noch nie etwas mit Grafikprogrammierung zu tun gehabt hat. Vor allem bei 3D-Computer- oder Konsolenspielen hört und liest man oft Dinge wie: „Das Spiel glänzt durch seine hervor-ragenden realistischen und hochauflösenden Texturen!“ Texturen sind in der Tat in der Lage, die Qualität eines gerenderten Bildes drastisch zu erhöhen, vor allem in Bezug auf die Reali-tätsnähe.

In der Realität ist fast keine Oberfläche so glatt und so „perfekt“ wie die des Dreiecks, das wir im vorherigen Beispielprogramm gezeichnet haben. Mit Texturen lassen sich Oberflächen recht gut simulieren, so kann zum Beispiel scheinbar aus einem vorher noch langweilig ausse-henden Dreieck ein dreieckiges Stück Holz werden. Texturen sind im Prinzip nichts weiter als Bilder, die charakteristische Muster und Farben der zu simulierenden Oberfläche zeigen. Die-se Bilder legt man dann beim Zeichnen über die Dreiecke.

Der schlagende Vorteil der Texturen ist, dass die 3D-Modelle, auf die sie gelegt werden, zur Simulation der Oberflächen nicht verfeinert werden müssen. Ein Dreieck bleibt ein Dreieck, und trotzdem sieht es später so aus, als ob es aus Hunderten von Teildreiecken bestünde, die ihm seine plastische Form verleihen. Das hat natürlich auch einen kleinen Nachteil: Betrachtet man eine Oberfläche in der Realität ganz genau, sieht man die kleinen darauf befindlichen Unebenheiten sehr deutlich. In der 3D-Grafik können gewöhnliche Texturen diesen Effekt nicht herbeirufen – das Dreieck bleibt von der Seite gesehen flach, egal, welche Textur darauf liegt. Trotzdem sind Texturen ein absolutes Muss für jede 3D-Engine, und sie haben noch ei-nen weiteren ungeheuren Vorteil: ihre Verarbeitungsgeschwindigkeit! Bei moderei-nen 3D-Grafikkarten merkt man jedoch von der Performance her fast keinen Unterschied mehr zwi-schen einem texturierten und einem nicht texturierten Dreieck.

Abbildung 2.28 Links: ohne Texturen; rechts: mit Texturen

2.6.1.2 Texturkoordinaten

Wie kann man es sich vorstellen, dass eine Textur über ein Dreieck gelegt wird? Es gibt ja un-endlich viele Möglichkeiten, wie das bewerkstelligt werden könnte. Stellen Sie sich die Textur wie Geschenkpapier vor und die Dreiecke wie das Geschenk, das Sie einpacken müssen. Weil die Frau gerade nicht zu Hause ist, muss Mann die Sache wohl selbst erledigen. Sollte man das Papier gerade um das Geschenk wickeln oder seitenverkehrt oder gedreht? Bei Texturen und Dreiecken kommt noch ein weiteres Problem hinzu: Wer entscheidet, wo bei einem Drei-eck oben und unten ist? Der Computer? Die Grafikkarte?

Der Programmierer beziehungsweise der Grafiker entscheidet über die Art und Weise, wie die Textur angewandt wird. Dazu erweitern wir das Vertexformat: Hinzu kommen nun noch weitere Koordinaten, die so genannten Texturkoordinaten. Die Texturkoordinaten, die gewöhnlich nur zweidimensional sind (die Texturen sind auch nur zweidimensionale Bilder) bestimmen, welcher Punkt, welcher Texel (Pixel einer Textur) auf der Textur dem Vertex zugeordnet wird. Die Textur-koordinaten werden beim Zeichnen ebenfalls über das ganze Dreieck interpoliert – ähnlich wie die Vertexfarben –, und der Rasterizer verwendet dann die Farbe der Textur an den Texturkoordinaten des gerade darzustellenden Pixels, um die endgültige Pixelfarbe festzulegen.

Mit den Texturkoordinaten erhält also jeder Vertex sozusagen sein Gegenüber auf der Textur.

Wie die Texturkoordinaten angeordnet sind, liegt ganz bei uns, hier gibt es (fast) keine Be-schränkungen.

Das zweidimensionale Texturkoordinatensystem besteht aus zwei Achsen: Die u-Achse zeigt nach rechts, und die v-Achse zeigt nach unten. Der Ursprung (0, 0) liegt hier nicht in der Mit-te, sondern in der linken oberen Bildecke. Die Einheiten der Texturkoordinaten sind nicht et-wa Pixel, sondern Bruchteile der Texturbreite und der Texturhöhe. So liegt der Punkt (1, 1) ganz rechts unten auf der Textur. Auf diese Art und Weise sind die Texturkoordinaten unab-hängig von der Größe der Textur. Der Punkt (0.5, 0.5) liegt bei jeder Textur – egal wie groß sie ist – genau in der Mitte.

Es sind auch Werte über 1 oder unter 0 möglich. Verlässt ein Wert den Bereich [0; 1], dann wiederholt sich die Textur wieder – sie wird gekachelt. So kann man eine Textur mehrfach nebeneinander über ein Objekt legen, was in der Praxis sehr oft nötig ist. Stellen Sie sich dazu eine sehr große dreidimensionale Landschaft vor, die mit einer Grastextur überzogen ist. Wür-de sich das eine Grasbild über die gesamte riesige Landschaft erstrecken, wäre nachher nichts mehr davon zu erkennen, da die Textur einfach zu stark auseinander gezogen wäre. Da bietet sich die Kachelung sehr gut an.

u-Achse

v-Achse (0, 0)

(1, 1)

0 0.5 1

00.51

gekachelter Bereich

Abbildung 2.29 Das Texturkoordinatensystem – gezeigt anhand einer Mauertextur

Beispiel

Wollte man das Dreieck aus dem letzten Beispielprogramm nun texturieren, könnte man das wie folgt tun: Dem obersten Vertex gäbe man die Texturkoordinaten (0.5, 0) – also die obere Mitte der Textur. Der rechte Vertex läge bei den Texturkoordinaten (1, 1) rechts unten und der linke Vertex bei (0, 1) links unten. Auf diese Weise würde die Textur nicht verzerrt. Würde man die Koordina-ten des rechKoordina-ten und des linken Vertex vertauschen, würde die Textur entlang der u-Achse gespie-gelt.

Die Vektorklassen tbVector2 und tbVector3 besitzen übrigens nicht nur Variablen namens x, y

und z, sondern auch welche namens u, v und w, die wir für Texturkoordinaten verwenden. u und x, v und y sowie w und z teilen sich jeweils den gleichen Speicherbereich (union). Wenn also x verändert wird, dann wird gleichzeitig auch u verändert. Hier handelt es sich also nur um eine alternative Schreibweise, um im Programm von Positions- und Texturkoordinaten un-terscheiden zu können.

2.6.1.3 Speicher und Größe

Texturen zählen zu den typischen Ressourcen von Direct3D. Bei ihnen ist der Speicher der Grafikkarte besonders beliebt, denn die Karte muss sehr oft und sehr schnell auf ihre Daten zugreifen können, um optimale Performance zu gewährleisten. Eine Textur ist im Prinzip nur eine Direct3D-Oberfläche. Einige Oberflächenformate sind speziell für Texturen vorgesehen und würden für einen Bildpuffer keinen Sinn machen.

Die Größe einer Textur ist übrigens nicht frei wählbar. Einerseits könnte eine sehr große Tex-tur Probleme machen, weil nicht genügend Speicher für sie vorhanden ist. Doch das ist nicht die einzige Beschränkung: Viele 3D-Grafikkarten akzeptieren nur solche Texturen, deren Breite und Höhe Zweierpotenzen sind, also 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048 und so weiter. Mit solchen Zahlen können die auf binärer Basis arbeitenden Mikroprozessoren viele Rechenoperationen viel schneller erledigen als mit Zahlen wie 67 oder 154. Manchmal kann es auch sein, dass eine Grafikkarte nur quadratische Texturen annimmt – also solche, bei denen Breite und Höhe gleich sind.

Welche Voraussetzungen eine Textur auf einem Adapter erfüllen muss, findet man durch Nachschauen in der D3DCAPS9-Struktur heraus:

ƒ Wenn Breite und Höhe Zweierpotenzen sein müssen, ist das Flag D3DPTEXTURECAPS_POW2 im

TextureCaps-Element der Struktur gesetzt.

ƒ Ist in der Struktur das Flag D3DPTEXTURECAPS_SQUAREONLY gesetzt (ebenfalls im Element

TextureCaps), müssen alle Texturen quadratisch sein.

Man sollte sich lieber gleich angewöhnen, nur mit quadratischen Texturen zu arbeiten, deren Breite beziehungsweise Höhe Zweierpotenzen sind, auch wenn so gut wie jede Grafikkarte Texturen mit beliebiger Breite und Höhe unterstützt. In der DirectX-SDK-Dokumentation steht, dass Texturen der Größe 256 x 256 Pixel am effizientesten gezeichnet werden.