Die Community zu .NET und Classic VB.
Menü

2D-Grafiken (2)

 von 

Einführung  

Dieses Kapitel war eigentlich dazu geplant, die Grundlagen von Texturen auf 2D-Primitiven zu behandeln. Dann habe ich gemerkt, dass das sehr ähnlich eines späteren Kapitels werden würde; da schreibe ich dann lieber ein ganzes Kapitel als zwei Halbe.

Texturen in Direct3D ist ein sehr großes Gebiet, JEDES Spiel, das Sie spielen, benutzt Mengen an Texturen - fast alles was gerendert wird, wird von Texturen beeinflusst. Texturen können Objekten leicht etwas realistisches geben - etwas, dass Farbe und Form diesem Objekt nie geben könnte.

Texturen, sobald Sie einmal die Hauptsache gelernt haben, sind sie sehr einfach zu benutzten; aber Sie MÜSSEN dies hier verstehen um mit dem etwas schwierigerem Zeug fertig zu werden. Textur-Blending, Animationen und Skinning könnten alle unter Texturen zusammengefasst werden - und ohne die Grundlagen, können Sie nie hoffen eine gute Engine zu schreiben.

Also, genug geredet. Es wird wieder Zeit für etwas Theorie...

Wieder etwas Theorie  

Es würde mich nicht wundern, wenn Sie langsam der Theorie ein bisschen überdrüssig würden - aber wenn Sie gut in DirectX werden wollen, dann ist diese Thoerie (wahrscheinlich) Ihr bester Freund. Hier eine Liste, mit allem was wir brauchen:

Was ist eine Textur? Eine Textur ist ein 2D-Bitmap, die in den Speicher geladen und dann um die Dreiecke gezogen wird. Bis jetzt haben Sie nur farbige Dreiecke gehabt - die Farbe wird in diesem Kapitel durch eine Textur ersetzt. Texturen haben den Nachteil, dass Sie schnell sehr viel Speicher fressen können - das ist wohl auch der Grund, warum der Speicher auf 3D-Grafikkarten immer mehr anwächst.
Texturkoordinaten: Texturkoordinaten sind NICHT in Pixeln - merken Sie sich das! Alle Texturkoordinaten liegen auf einer Skala von 0.0 bis 1.0; wo 0.0 der Minimalwert und 1.0 der Maximalwert ist(256 für eine 256x256 Texture, 512 für eine 512x512 Textur und so weiter...). Wenn Sie immer noch Pixel benutzten wollen, dann können die Texturkoordinate so berechnen: TexKoord = (1/ MaxTexturGröße) * PixelKoord Das ist noch nicht richtig schwer, ist aber wieder eine Sache die man sich meken sollte. 256 als Texturkoordinate wird entweder nichts machen oder ein paar wirklich verrückte Sachen passieren lassen...
Texturgrößen: Die Texturgrößen können einen manchmal ziemlich auf die Nerven gehen. Alle Größen müssen immer ein Quadrat aus 2 (2^x) sein. (Zum Beispiel: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,...) Das heißt, dass die Textur immer größer und größer wird je größer ,x' wird - was richtig ärgerlich wird, wenn Sie eine Textur mit der Größe 800x800 benutzten wollen(Nächste Wert: 512x512 und 1024x1024). Allerdings ist es sowieso unpraktisch Texturen über 256x256 zu benutzten. Manche Hardware unterstützt Sie nicht, die Andere läuft mit größeren Texturen viel langsamer. Also seinen Sie realistisch, wenn Sie ihre Texturen zeichnen. Es nutzt nicht eine super-detaillierte Textur zu zeichnen, die immer nur auf einen kleinen Bereich sichtbar ist - die Details sind so nie sichtbar und bremsen eher die Hardware ab.
Lighting(Beleuchtung): Bis jetzt haben wir Lighting noch nicht richtig besprochen(und werden das hier auch nicht tun), allerdings müssen Sie wissen, das Lighting kontrolliert, wie die Verticen angezeigt werden. In der letzten Lektion zeigt sich dies durch die Farben, die rund um das Rechteck geblendet werden. Diese Farben sind einfach nur Licht; und die Texturen werden dann nach dieser Farbe geändert. Z.B. eine Textur auf grünen Verticen, wird die Textur leicht Grün färben.

Eine Textur laden und anzeigen  

Dann können wir jetzt anfangen, mit Texturen rumzuspielen... Wir ändern einfach nur den Code aus Lektion 3, so, dass wir nun anstatt schöner bunter Formen, schöne texturierte Formen bekommen. Dieser erste Teil ist sehr einfach; aber es wird noch ein bisschen schwerer werden.

Zuerst müssen wir zwei Deklarationen hinzufügen:

Dim D3DX As D3DX8 'A helper library
Dim Texture As Direct3DTexture8

Das D3Dx-Objekt ist etwas dem wir später wieder begegnen werden - also kann ich es gleich jetzt vorführen. D3Dx ist eine Hilferklasse, sie enthält viele nutzvolle Funktionen, die bestimmte Aufgaben einfacher machen. Die meisten sind für Geometrieerstellung, Gittermanipulierung, Texturenladen und manche einfachen Mathefunktionen - wie Matrizen oder Lichtstrahlüberschneidungen(welche überhaupt nicht einfach sind) Zweitens müssen wir diese Zeilen in unsere Initialisierungssub eintragen:

  'Diese Zeile kann nach der DirectX -
  'Objekt und Direct3Ddevice Erstellung kommen
Set D3DX = New D3DX8 'Helferlibrary erstellen
  'Egal wie die obige Zeile muss vor diesem Aufruf kommen.
  '/Jetzt laden wir unsere Textur
Set Texture = D3DX.CreateTextureFromFile(D3DDevice, App.Path & _
  "\ExampleTexture.bmp")

Jetzt haben wir eine richtige Textur im Speicher. Bis jetzt ist das noch nicht schwierig; der D3DX.CreateTextureFromFile-Aufruf ist so einfach, dass ich mir nicht denken kann, wie irgendjemand ihn falsch haben könnte. Später benutzen wir den CreateTextureFrom-FileEx-Aufruf, welche uns etwas mehr Kontrolle über die Textur gibt - mit dem Nachteil, dass der Aufruf dann komplizierter wird...


Abbildung 1: Beispiel für Texturkoordiaten

Die wichtigste Sache, die wir an unserer Geometrie verändern müssen, sind die Texturkoordinaten. Dies ist, wenn wir mit Vierecken arbeiten ziemlich einfach. Wenn Sie später mit obskuren Formen arbeiten wollen, wird dies extrem schwieriger. Um die Texturkoordinaten zu verändern, übergeben wir sie einfach in den letzten zwei Parametern. Für unser Rechteck brauchen wir einen Code wie den:

  'vertex 0
TriStrip(0) = CreateTLVertex(10, 10, 0, 1, RGB(255, 255, 255), _
  0, 0, 0)
  'vertex 1
TriStrip(1) = CreateTLVertex(210, 10, 0, 1, RGB(255, 0, 0), _
  0, 1, 0)
  'vertex 2
TriStrip(2) = CreateTLVertex(10, 210, 0, 1, RGB(0, 255, 0), _
  0, 0, 1)
  'vertex 3
TriStrip(3) = CreateTLVertex(210, 210, 0, 1, RGB(0, 0, 255), _
  0, 1, 1)

Der obige Code ist ziemlich der selbe, wie wir ihn im letzten Kapitel hatten; nur das jetzt die Texturkoordianten hinzugefügt sind. Zuletzt müssen wir noch die Verticen rendern, die wir gerade erstellt habe. Dies ist mal wieder ziemlich einfach:

D3DDevice.SetTexture 0, Texture
  'Dem Device angeben, welche Textur wir benutzen
D3DDevice.DrawPrimitiveUP D3DPT_TRIANGLESTRIP, 2, _
  TriStrip(0), Len(TriStrip(0))

Die zweite Zeile sollten Sie schon kennen, der erste auch kaum kompliziert. Der 0 Parameter ist für Multiple Textureblending und andere Textur-Spezialeffekte reserviert - aber im Moment wollen wir nichts daran ändern. Wenn alles gut klappt, dann sollten Sie etwas wie dieses Bild sehen:


Abbildung 2: Ein Figur mit Textur

Im Bild werden Sie wahrscheinlich bemerkt haben:

  • wir haben zwei Quadrate
  • sie haben verschiedene Farben

Im Beispielcode dieses Kapitels habe ich zwei Quadrate erstellt, um etwas bestimmtes zu erklären; der Code ist aber fast der selbe geblieben. Lighting oder die Vertexfarbe bestimmen teilweise, wie die Textur angezeigt wird. Normalerweise ist diese Textur grau (wie im rechten Quadrat), aber wenn wir eine Textur für nicht-weiße Verticen benutzen, dann bekommen wir diese Färbung.

Das ist ein Teil des Direct3D-Lighting. Es verändert die Vertexfarbe, was dann die Textur ändert. Das kann ziemlich praktisch werden; weiße Verticen ändern gar nichts, graue machen die Textur dunkler, farbige enden in einer Färbung der Textur.

Es gibt aber einen kleine Haken auf den wir aufpassen müssen. Sie sollten sich immer merken, wie Farben in Direct3D erstellt werden. Nätürlich wieder in Rot-, Grün- und BlauwertenWenn die Farbe eines Vertex 0,5 beträgt, dann wird die Farbe aller näheren Pixel halbiert(sie werden dunkler). Was passiert aber, wenn die Textur komplett rot ist, das Licht hingegen aber grün? Das Licht multipliziert alle Rot- und Grünwerte mit 0 und alle Grünen mit 0,75(oder so); d.h. die Rotwerte werden mit 0 multipliziert, was 0 ergibt, die Blauwerte werden ebenfalls mit 0 multipliziert, wieder 0. Zuletzt werden die Grünwerte mit 0,75 multipliziert - in einer roten Textur gibt es aber keine Grünwerte, so das es wieder 0 ergibt. Die Farbe ist also 0,0,0 - schwarz. Es gibt Wege, um das zu vermeiden, wir besprechen sie aber erst später(im Kapitel über Lighting).

Transparente Grafiken  

An diesem Punkt sollten Sie fähig sein ein 2D-Spiel zu schreiben - wahrscheinlich ein seht einfaches, aber es ist nicht unmöglich. Sie könne eine 2D-Geometrie erstellen und denen Texturen zuweisen. Das einzigste über, was Sie für schöne 2D-Grafiken noch wissen müssen, ist wie man transparente Grafiken zeichnet.

Transparente Grafiken sind jene, in denen der Renderer bestimmte Teile einer Textur nicht mitrendert. Dies erlaubt Ihnen hochkomplizierte Formen mit einer geringen Vertexanzahl. Sie könnten zwar eine runde Form mit Verticen erstellen, Sie würden dafür aber wahrscheinlich Hunderte benötigen; mit transparente Grafiken könnten Sie einfach eine transparente Textur einem Rechteck zuweisen(mit nur zwei Dreiecken).

Um transparente Grafiken zu benutzen, müssen wir diese drei Aufrufe in unsere Initialisierungssub schreiben:

D3DDevice.SetRenderState D3DRS_SRCBLEND, D3DBLEND_SRCALPHA
D3DDevice.SetRenderState D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA
D3DDevice.SetRenderState D3DRS_ALPHABLENDENABLE, True

Zuerst sagen wir Direct3D, was für einen Typ transparenter Grafiken wir benutzen wollen(es gibt ein paar Möglichkeiten), dann schalten wir Alpha Blending an. Erstens: Alpha Blending ist ein ziemlich erweitertes Thema, aber (leider) brauchen wir es um Grafiken transparent zu zeichnen; wir werden in einem späteren Kapitel noch mal darauf zurückkommen. Zweitens: Wir stellen Alpha Blending von Start an ein, obwohl es eigentlich besser ist, wenn wir es aus lassen und nur anschalten, wenn wir es benötigen(an vor dem DrawPrimativeUP-Aufruf, aus danach). Etwas anderes, was Sie später noch herausfinden werden, ist, dass die SRCBLEND und DESTBLEND Faktoren das gesamte Rendering beeinflussen; also ist es keine gute Idee es dauernd anzulassen.

Um eine transparente Textur zu laden benutzen wir eine neue Funktion - diesmal eine etwas längere als die alte:

'Benutzen Sie eine der folgenden, davon abhängig, was Sie
'brauchen. Andere Farben ließen sich auch einstellen, aber
'diese sollten für das meiste gehen.
'ColorKeyVal = &HFF000000 '//Schwarz
'ColorKeyVal = &HFFFF0000 '//Rot
ColorKeyVal = &HFF00FF00 '//Grün
'ColorKeyVal = &HFF0000FF '//Blau
'ColorKeyVal = &HFFFF00FF '//Magenta
'ColorKeyVal = &HFFFFFF00 '//Gelb
'ColorKeyVal = &HFF00FFFF '//Cyan
'ColorKeyVal = &HFFFFFFFF '//Weiß
Set TransTexture = D3DX.CreateTextureFromFileEx(D3DDevice, _
  App.Path & "\transtexture.bmp", 64, 64, D3DX_DEFAULT, _
  0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_FILTER_POINT, _
  D3DX_FILTER_POINT, _
  ColorKeyVal, ByVal 0, ByVal 0)

Die ersten Teile sind nur eine bisschen Faulheit - durch kommentieren oder entkommentieren können Sie schnell eine andere Farbe als transparente benutzen. Der CreateTexturFromFileEx hat ein paar Parameter, die Sie kennen sollten; Es ist aber unwahrscheinlich, dass Sie je alle davon brauchen:

    <center>

 object.CreateTextureFromFileEx( _
      Device As Direct3DDevice8, _
      SrcFile As String, _
      Width As Long, _
      Height As Long, _
      MipLevels As Long, _
      Usage As Long, _
      Format As CONST_D3DFORMAT, _
      Pool As CONST_D3DPOOL, _
      Filter As Long, _
      MipFilter As Long, _
      ColorKey As Long, _
      SrcInfo As Any _
      Palette As Any) As Direct3DTexture8
</center>

Hier die Beschreibung:

Object: Ein initialisiertes D3DX-Objekt
Device: Ihr Render-Device
SrcFile Ein String, der angibt, woher die Textur geladen werden soll.
Width: Breite in Pixeln, natürlich wieder mal als Quadrat von 2(32, 64, ...). Sie können D3DX_DEFAULT benutzen, damit Direct3D entscheidet in welcher Breite es die Textur lädt(die Breite, in der Sie das Bild gespeichert haben.
Height: Das gleiche wie die Breite, nur für die Höhe.
MipLevels: Wie viele MipLevel erstellt werden. Diese werden in einem späteren Kapitel behandelt. Im Moment lassen Sie es einfach auf D3DX-DEFAULT oder auf 1(Nur ein Level wird erstellt)
Usage: Sie können diese Textur als ein Renderziel definieren(gut für Spezialeffekte), für die normale Benutzung lassen Sie es aber mal auf 0.
Format: Welches Format die Textur hat; das selbe, wie wenn Sie das Format für den Backbuffer angeben. Wenn Sie etwas clever sein sollen, dann übergeben Sie einfach D3DFMT_UNKNOWN und Sie brauchen das Format nicht angeben.
Pool: Wo der Speicher für die Textur angelegt werden soll; bestimmte Bereiche sind schneller als Andere. D3DPOOL_MANAGED sollte reichen, die anderen Möglichkeiten werden später erklärt.
Filter: Welchen Texturfilter wir benutzen wollen. Das beeinflusst nur Texturen die irgendwie eingedrückt oder hervorgezogen sind - was nur passieren wird, wenn Sie in richtiges 3D übergehen werden. Normalerweise benutzen wir D3DX_FILTER_LINEAR, für einfach Sachen D3DX_FILTER_POINT und für die beste Qualität D3DX_FILTER_TRIANGLE. Experimentieren Sie mit dieser Einstellung ein bisschen herum; manche sehen in bestimmten Situationen besser aus.
MipFilter: Das selbe wie das obere Parameter, nur für MipMaps.
ColorKey: Welche Farbe transparent ist - dieser Parameter erwartet einen 32-Bit ARGB-Code, am Besten als Hexadezimale Nummer. Sie sollten sich mittlerweile an die hexadezimale RGB-Notation gewöhnt haben. Dies ist allerdings ein Wert im &HFF Format. Alles was passieren wird, ist das alle Pixel in dieser Farbe nicht gerendert werden.
SrcInfo: Erlaubt eine D3DXIMAGE-Struktur zu übergeben, die Informationen über das Bild enthält(Höhe, Breite, Farbtiefe, ...). Wird aber nicht richtig benötigt, also lassen Sie es auf ByVal 0
Palette: Lassen Sie das auch auf ByVal 0. Paletten sind auf dem Weg aus Direct3D rauszufallen(sogar "alte" Karten unterstützen besseres) Sie bieten nur wenig Geschwindigkeitsvorteil und können nebenbei noch schön schlecht aussehen...

Beispielprojekt zum Tutorial [29000 Bytes]

Ihre Meinung  

Falls Sie Fragen zu diesem Tutorial haben oder Ihre Erfahrung mit anderen Nutzern austauschen möchten, dann teilen Sie uns diese bitte in einem der unten vorhandenen Themen oder über einen neuen Beitrag mit. Hierzu können sie einfach einen Beitrag in einem zum Thema passenden Forum anlegen, welcher automatisch mit dieser Seite verknüpft wird.