Die Community zu .NET und Classic VB.
Menü

Einfache 3D-Grafiken

 von 

Einführung  

Willkommen in Kapitel 5. Höchstwahrscheinlich wissen Sie jetzt, wie Sie eine Direct3D-Anwendung initialisieren und ein paar einfache zweidimensionale mit Texturen rendern können; das ist perfekt, wenn Sie ein 2D-Spiel programmieren wollen, aber kaum interessant, wenn es zu neusten 3D-Grafiken kommt. Und das ist es was dieses Kapitel versucht. Am Ende dieses Kapitels sollten Sie fähig sein ihre erste 3D-Welt zu erstellen - zwar nicht mit den tollsten Grafiken und Effekten, aber es ist ein Schritt in die richtige Richtung.

Leider ist dieses Kapitel sehr lang - es gibt 3 neue wichtige Features, die ich Ihnen vorstellen muss: 3D-World-Space, Vertex Buffer, Matrizen, Tiefenbuffer und Culling. Diese Themen sind die Basis aller 3D-Grafiken; also müssen Sie sie lernen.

3D-Grafik Theorie  

Wieder mal ein Kapitel mit massenhaft Theorie am Anfang; diese mal wird's aber richtig wichtig - ignorieren Sie das hier, dann werden Sie sehr schnell hängen bleiben. Wie ich oben gesagt habe ist dieser Kram die Basis selbst der einfachsten 3D-Engine.

3D-World-Space: Das ist nicht wirklich schwierig - es ist nur eine Fortsetzung von dem was Sie in Kapitel 3 gelernt haben. Sie können die Welt in verschiedenen Arten initialisieren; normalerweise ist die +Y-Achse nach "oben", -Y nach "unten" (obwohl die Kameraposition das schön durcheinander bringen kann.). 3D Koordinaten sind auf drei Achsen definiert - X, Y und Z. Wenn Sie genau die Z-Achse entlang schauen, dann wird +Y oben sein, +X rechts, +Z genau hinter Ihnen, -Y unten, -X links und -Z vor Ihnen(die Entfernung). Natürlich kann die Kamera alles durcheinander bringen...
Vertex Buffer: Vertex Buffer sind in der Weise ähnlich zu Texturen, dass Sie vorerstellte Daten enhiddenthalten. Vertex Buffer zu benutzten kann sehr viel helfen, wenn es zu komplizierten 3D-Szenen kommt - anstatt Hunderte Verticen in verschiedene Arrays zu legen, können Sie diese einfach in einen Vertex Buffer laden und mit ein paar wenigen Aufrufen rendern. Sie sind nicht schwierig zu initialisieren oder zu benutzen - aber Sie sollten von deren Existenz wissen.
Matrizen: Das ist ein lustiges Thema, Matrizen (Plural von Matrix) sind in Wirklichkeit ein fortgeschrittenes mathematisches Thema - welches Sie nur kennengelernt haben werden, wenn Sie fortgeschrittene Mathekurse besuchen (oder besucht haben). Es ist nicht schlimm, wenn Sie ihren vollen mathematischen Nutzen nicht verstehen, aber es ist wichtig, dass Sie wissen, wie sie funktionieren und noch wichtiger: wie man sie benutzt. Es gibt drei Typen von Matrizen, die Sie benutzen werden: World Matrix, View Matrix und Projection Matrix. Die World Matrix verändert, wie die Verticen gezeichnet werden - wenn Sie rotierte Matrizen benutzen, dann werden alle Verticen um diese Anzahl gedreht (die originalen Daten werden nicht verändert). Die View Matrix ist einfach die Kamera - diese Matrix definiert, wo das "Auge" ist und wo es hinschaut (2 Koordinaten im 3D-World-Space). Sie können auch definieren, welche Richtung oben ist; normalerweise benutzt man die +Y-Achse, aber das muss nicht sein. Die Projection Matrix beschreibt, was Direct3D auf dem Bildschirm rendert - das Sichtfeld (FOV - Field Of View).
Tiefenbuffer: Diese sind sehr brauchbar; einfach zu initialisieren und wenn sie einmal initialisiert sind, dann muss man sie nicht mehr viel beachten - sie sind nur da und arbeiten. Überlegen Sie sich das: Sie zeichnen zwei Dreiecke in eine 3D-Welt - wie wissen Sie, welches Dreieck vor dem anderen ist und wenn sie sich überschneiden, welchen Teil Sie rendern müssen? Ein Tiefenbuffer löst das - wenn Sie eine Dreieck zum Rendern senden, dann wird der Abstand von der Kamera in einem Tiefenbuffer gespeichert. Wenn ein anderes Dreieck gerendert wird, dann wird entschieden, welches Pixel gezeichnet wird, indem die Tiefe(Entfernung von der Kamera) berechnet und mit der Tiefe des an der selben Position existierenden Pixel verglichen wird. Wenn die Tiefe geringer ist, dann wird das bestehende Pixel ersetzt, wenn sie größer ist, dann wird das Pixel nicht gezeichnet(weil etwas davor ist). Tiefenbuffer kommen in verschieden Tiefen - 16 Bit, 24 Bit, und manchmal 32 Bit; je höher die Tiefe, desto besser die Qualität, aber auch die Berechnungszeit dafür. Tiefenbuffer sind auch als Z-Buffer bekannt.
Culling: Normalerweise rendert Direct3D keine Dreiecke, die von der Kamera wegzeigen - das ist gut, weil alles dadurch ein gutes Stück schneller wird. Sie können auch ändern, was Direct3D cullt; normalerweise werden Dreiecke weggelassen, deren Verticen in Gegen-Uhrzeigersinn angeordnet sind und lässt die im Uhrzeigersinn da. Sie können leicht herausfinden wir ihre sind - ob die Verticen im Uhrzeigersinn geordnet sind(z.B. Links-Rechts-Unten) oder ob sie gegen den Uhrzeigersinn angeordnet sind(z.B. Unten-Rechts-Links). Sie können auch einstellen, dass Direct3D keine Dreiecke weglässt, was aber einen größen Geschwindigkeitsverlust bewirkt(aber gut zum Debuggen ist).

Tiefenpuffer  

Tiefenbuffer, wie ich oben schon gesagt habe, sind extrem einfach zu initialisieren, und sobald sie das sind kann man ihre Existenz meistens ignorieren. Um sie zu initialisieren, können Sie diesen Code benutzen, eine leichte Änderung des alten Codes:

'## INITIALISE() CODE ##
D3DWindow.EnableAutoDepthStencil = 1
D3DWindow.AutoDepthStencilFormat = D3DFMT_D16 '16 bit Z-Buffer
 'Nachdem wir den D3DDevice erstellt haben
 'Z-Buffer
D3DDevice.SetRenderState D3DRS_ZENABLE, 1

Sehr gut, jetzt haben wir einen funktionierenden Z-Buffer in unserem Device. Wenn Sie diesen Aufruf nicht vergessen, dann ist alles gut. Sie müssen natürlich aufpassen, dass Sie überhaupt Hardwareunterstützung für die ausgewählte Buffertiefe haben. Wenn Sie eine Tiefe wählen, die nicht unterstützt wird, dann können zwei Dinge passieren:

  • Das Device fällt in einen Modus zurück, der unterstützt wird.
  • Der Tiefenbuffer wird nicht initialisiert

Beides ist nicht gerade super, deswegen hier ein Stück Code mit dem Sie heruasfinden, welche Tiefen unterstützt werden:

If D3D.CheckDeviceFormat(D3DADAPTER_DEFAULT, _
  D3DDEVTYPE_HAL, DispMode.Format, D3DUSAGE_DEPTHSTENCIL, _
  D3DRTYPE_SURFACE, D3DFMT_D16) = D3D_OK Then
    'Wir benutzen einen 16Bit Buffer
  D3DWindow.AutoDepthStencilFormat = D3DFMT_D16
    '16 bit Z-Buffer
Else
  'Hier könnten wir auf verschiedene andere Modi testen
End If

Wenn Sie nach anderen Modi suchen wollen, können Sie diesen Code benutzen:

If D3D.CheckDeviceFormat(D3DADAPTER_DEFAULT, _
  D3DDEVTYPE_HAL, DispMode.Format,   D3DUSAGE_DEPTHSTENCIL, _
  D3DRTYPE_SURFACE, D3DFMT_D16) = D3D_OK Then
    Debug.Print "16 bit Z-Buffers werden" &
      unterstützt  (D3DFMT_D16)
End If
If D3D.CheckDeviceFormat(D3DADAPTER_DEFAULT, _
  D3DDEVTYPE_HAL, DispMode.Format,   D3DUSAGE_DEPTHSTENCIL, _
  D3DRTYPE_SURFACE, D3DFMT_D16_LOCKABLE) = D3D_OK Then
    Debug.Print "Lockable 16 bit " &
      Z-Buffers werden unterstützt (D3DFMT_D16_LOCKABLE)
End If
If D3D.CheckDeviceFormat(D3DADAPTER_DEFAULT, _
  D3DDEVTYPE_HAL, DispMode.Format, D3DUSAGE_DEPTHSTENCIL, _
  D3DRTYPE_SURFACE, D3DFMT_D24S8) = D3D_OK Then
    Debug.Print "32Bit aufgeteilt in 24Bit" &
     Tiefe und 8Bit Stencil werden unterstützt (D3DFMT_D24S8)
End If
If D3D.CheckDeviceFormat(D3DADAPTER_DEFAULT, _
  D3DDEVTYPE_HAL, DispMode.Format, D3DUSAGE_DEPTHSTENCIL, _
  D3DRTYPE_SURFACE, D3DFMT_D24X4S4) = D3D_OK Then
   Debug.Print "32 bit aufgeteilt in 24 bit depth," &
      4 bit stencil und 4 bit unused (D3DFMT_D24X4S4)
End If
If D3D.CheckDeviceFormat(D3DADAPTER_DEFAULT, _
  D3DDEVTYPE_HAL, DispMode.Format,   D3DUSAGE_DEPTHSTENCIL, _
  D3DRTYPE_SURFACE, D3DFMT_D24X8) = D3D_OK Then
   Debug.Print "24 bit Z-Buffer " &
     werden unterstützt  (D3DFMT_D24X8)
End If
If D3D.CheckDeviceFormat(D3DADAPTER_DEFAULT, _
  D3DDEVTYPE_HAL, DispMode.Format,   D3DUSAGE_DEPTHSTENCIL, _
  SURFACE, D3DFMT_D32) = D3D_OK Then
   Debug.Print "Pure 32 bit Z-buffer " &
     werden unterstützt  (D3DFMT_D32)
End If

Vertexbuffer  

Geometrieerstellung in 3D ist nicht sehr viel schwieriger, als in 2D, der einzige Unterschied ist es, dass man 3 Dimensionen benutzt anstatt 2. Erst wenn wir mit Lighting herumspielen, wird es ein wenig schwieriger.

Das erste, was wir machen müssen, ist ein neues Vertexformat einzustellen; wir werden eines nehmen, dass mit dem D3DLVERTEX aus DirectX7 gleich ist; wir geben Direct3D eine Position und eine Farbe und es transformiert diese.

'Wir benutzen 3D Verticen, aber noch kein Lighting, d.h.
' wir müssen eine Farbe definieren
Private Type LITVERTEX
  x As Single
  y As Single
  z As Single
  color As Long
  Specular As Long
  tu As Single
  tv As Single
End Type
'Die Bechreibung dieses Vertexformats
Const Lit_FVF = (D3DFVF_XYZ Or D3DFVF_DIFFUSE Or _
  D3DFVF_SPECULAR Or D3DFVF_TEX1)
Dim Cube(35) As LITVERTEX

Hier ist auch die Deklaration für unsere Geometrie; 36 Verticen für einen einfachen Würfel hört sich sehr viel an; ist es auch. Mit anderen Methoden(Kapitel 9), könnten wir einen Würfel mit 8 Verticen machen. Wenn wir Dreieckstrips benutzen würden, kämen wir auch schon auf 24 herunter - es würde aber schwerer werden, Sie in einen Vertex Buffer zu schreiben.

Wir schreiben jetzt unsere InitialiseGeometry()-Funktion so um, dass sie einen Würfel erzeugt. Zwei Sachen an diesem Code:

Ich habe mich nicht um die Vertexreihenfolge gekümmert (wegen des Cullings)
Alle Verticen sind um den Nullpunkt erstellt - die Mitte des Würfels liegt bei (0|0|0).Spätestens wenn Sie den Teil über Matrizen gelesen haben, dann wissen Sie warum.

Const C000 As Long = 255     'Rot
Const C001 As Long = 65280  'Grün
Const C100 As Long = 16711680   'Blau
Const C101 As Long = 16711935 'Magenta
Const C010 As Long = 65535 'Gelb
Const C011 As Long = 16776960 'Cyan
Const C110 As Long = 16777215 'Weiß
Const C111 As Long = 8421631 'Orange
' Die Strunktur mit Daten füllen
    'Vorne
  Cube(0) = CreateLitVertex(-1, 1, 1, C011, 0, 0, 0)
  Cube(1) = CreateLitVertex(1, 1, 1, C111, 0, 0, 0
  Cube(2) = CreateLitVertex(-1, -1, 1, C001, 0, 0, 0)
  Cube(3) = CreateLitVertex(1, 1, 1, C111, 0, 0, 0)
  Cube(4) = CreateLitVertex(-1, -1, 1, C001, 0, 0, 0)
  Cube(5) = CreateLitVertex(1, -1, 1, C101, 0, 0, 0)
    'Hinten
  Cube(6) = CreateLitVertex(-1, 1, -1, C010, 0, 0, 0)
  Cube(7) = CreateLitVertex(1, 1, -1, C110, 0, 0, 0)
  Cube(8) = CreateLitVertex(-1, -1, -1, C000, 0, 0, 0)
  Cube(9) = CreateLitVertex(1, 1, -1, C110, 0, 0, 0)
  Cube(10) = CreateLitVertex(-1, -1, -1, C000, 0, 0, 0)
  Cube(11) = CreateLitVertex(1, -1, -1, C100, 0, 0, 0)
   'Rechts
  Cube(12) = CreateLitVertex(-1, 1, -1, C010, 0, 0, 0)
  Cube(13) = CreateLitVertex(-1, 1, 1, C011, 0, 0, 0)
  Cube(14) = CreateLitVertex(-1, -1, -1, C000, 0, 0, 0)
  Cube(15) = CreateLitVertex(-1, 1, 1, C011, 0, 0, 0)
  Cube(16) = CreateLitVertex(-1, -1, -1, C000, 0, 0, 0)
  Cube(17) = CreateLitVertex(-1, -1, 1, C001, 0, 0, 0)
    'Links
  Cube(18) = CreateLitVertex(1, 1, -1, C110, 0, 0, 0)
  Cube(19) = CreateLitVertex(1, 1, 1, C111, 0, 0, 0)
  Cube(20) = CreateLitVertex(1, -1, -1, C100, 0, 0, 0)
  Cube(21) = CreateLitVertex(1, 1, 1, C111, 0, 0, 0)
  Cube(22) = CreateLitVertex(1, -1, -1, C100, 0, 0, 0)
  Cube(23) = CreateLitVertex(1, -1, 1, C101, 0, 0, 0)
   'Oben
  Cube(24) = CreateLitVertex(-1, 1, 1, C011, 0, 0, 0)
  Cube(25) = CreateLitVertex(1, 1, 1, C111, 0, 0, 0)
  Cube(26) = CreateLitVertex(-1, 1, -1, C010, 0, 0, 0)
  Cube(27) = CreateLitVertex(1, 1, 1, C111, 0, 0, 0)
  Cube(28) = CreateLitVertex(-1, 1, -1, C010, 0, 0, 0)
  Cube(29) = CreateLitVertex(1, 1, -1, C110, 0, 0, 0)
    'Unten
  Cube(30) = CreateLitVertex(-1, -1, 1, C001, 0, 0, 0)
  Cube(31) = CreateLitVertex(1, -1, 1, C101, 0, 0, 0)
  Cube(32) = CreateLitVertex(-1, -1, -1, C000, 0, 0, 0)
  Cube(33) = CreateLitVertex(1, -1, 1, C101, 0, 0, 0)
  Cube(34) = CreateLitVertex(-1, -1, -1, C000, 0, 0, 0)
  Cube(35) = CreateLitVertex(1, -1, -1, C100, 0, 0, 0)

Sieht gut aus, oder? Stellen Sie sich jetzt nur mal vor damit eine Landschaft oder eine Person zu machen... das ist auch der Grund, warum wir vorerstellte laden und direkt anzeigen. Sie werden wahrscheinlich bemerkt haben, dass ich Konstanten für die Farben benutzt habe - ein Würfel hat 8 Ecken, also auch 8 Farben - für jede Ecke eine. Weil 3 oder 4 Verticen die selbe Farbe haben können, habe ich die Konstanten eingebaut; wenn Sie die Konstanten ändern, dann ändern alle Verticen mit der selben Position ihre Farbe.

Sie werden wohl auch bemerkt haben, dass ihr noch nichts über die Vertex Buffer gesagt habe. Also... Vertex Buffer sind nur eine zusammenhängender Block Speicher, der von Direct3D so formatiert ist, dass es die Daten schneller erreichen kann. Der erste Schritt ist es genug Speicher für den Vertex Buffer freizugeben und ihn dann mit den Cube()-Daten füllen, die wir gerade definiert haben. Um das zu tun benutzen wir diesen Code:

'Einen leeren Vertex Buffer in der benötigen Größe anlegen
Set VBuffer = D3DDevice.CreateVertexBuffer(_
  Len(Cube(0)) * 36, 0, Lit_FVF, D3DPOOL_DEFAULT)
If VBuffer Is Nothing Then Exit Function 'Fehlerhandler
  'Den erstellten Buffer mit Daten füllen
D3DVertexBuffer8SetData VBuffer, 0, Len(Cube(0)) * 36, _
  0, Cube(0)

Merken Sie sich, dass wir die Größe des Buffers in Byte einstellen müssen - das MUSS passen, oder wir bekommen ein Problem; zu klein und Sie bekommen Ärger, wenn Sie den Buffer füllen, zu groß und Sie verschwenden Speicher. Die Größe ist immer

Größe eines Vertex * Nummer der Verticen
Wir benutzen die Len()-Funktion um die Größe zu bekommen, dann multiplizieren wir den Wert mit der Anzahl Verticen, die wir haben(36). Wir müssen auch das Vertexformat übergeben, damit Direct3D weiß, was es da geliefert bekommt; zuletzt bestimmen wir noch wie Direct3D den Speicher managen soll. D3DPOOL_DEFAULT sollte genügen, ansonsten benutzen Sie D3DPOOL_MANAGED(Direct3D entscheidet, und tu es dahin wo's passt) oder D3DPOOL_SYSTEMMEM(im Systemspeicher ablegen(RAM)).

Im nächsten Aufruf benutzten wir eine versteckte Funktion(oder so). Wir geben ihr den Namen unseres Vertexbuffers, die Größe des Bereichs, welchen wir füllen wollen und die Stelle an dem wir mit dem Füllen beginnen wollen. Zuletzt übergeben wir noch das Array von Daten, welches wir benutzen wollen; dieses muss im selben Format wie der Buffer sein, oder ein paar verrückte Dinge könnten passieren.

Vorausgesetzt nichts ist schiefgegangen, können wir zu einem interessanterem Teil übergehen...

Matrizen  

Matrizen sind extrem brauchbar, wenn man sie versteht; mit ihnen kann man eine enorme Menge in einer 3D-Welt anstellen. Matrizen ist ein ziemlich kompliziertes mathematisches Thema - deshalb werde ich jetzt nicht erklären wie sie funktionieren - sondern nur, wie Sie sie verwenden können. Eine Matrix, in Direct3D, ist eine 4x4 Matrix - denken Sie sie sich als eine Tabelle, jeweils vier Einträge lang und hoch. Direct3D benutzt die Zahlen (in den Matrizen), um verschiedene Sachen während der Low-Level Berechnung zu verändern - also nachdem sie die Aufrufe zum Rendern geschickt haben, aber bevor sie auf dem Bildschirm erscheinen.

Es gibt ein paar Dinge, die sie sich merken sollten, wenn Sie Matrizen benutzen:

  1. Sie können Matrizen zu einer neuen kombinieren; zum Beispiel wenn Sie eine Rotation und eine Translationmatrix kombinieren, dann bekommen Sie eine Matrix, die alles rotiert und übersetzt, was ihr gegeben wird.
  2. Im Gegensatz zu normalen Zahlen wo (a*b) = (b*a) gibt [A]*[B] nicht [B]*[A] - also ist es wichtig, dass Sie alles Richtigrum machen.
  3. Es gibt eine Menge Funktionen in der D3DX8-Bibliothek, die helfen Matrizen zu manipulieren
  4. Es gibt drei Matrizen, die Sie hauptsächlich benutzen werden; es gibt natürlich andere für verschiedene Effekte. Diese drei werden unten beschrieben:

World Matrix:

Diese Matrix verändert die Verticen - sie werden sie wahrscheinlich am Meisten benutzen. Alle Transformationen der Verticen gehen rund um Mittelpunkt([0,0,0]) - es rotiert Verticen um den Mittelpunkt, es skaliert Verticen um den Mittelpunkt. Das ist der Grund, warum wir vorher unseren Würfel um den Mittelpunkt erstellt haben.

Wie es gesagt wurde, ist es möglich mehrere Matrizen zu einer zu kombinieren; sie sollten sich aber immer daran erinnern, dass die Reihenfolgen in der Sie sie kombinieren wichtig ist. Wenn Sie etwas erst um die X-Achse, dann um die Z-Achse rotieren, dann bekommen Sie nicht das selbe Ergebnis, wie wenn Sie erst um die Z-Achse und dann um die X-Achse rotieren.

Der folgende Code ist vom Beispiel des Kapitels:

Dim matWorld As D3DMATRIX
Dim matTemp As D3DMATRIX

D3DXMatrixIdentity matWorld 'Reset our world matrix
D3DXMatrixIdentity matTemp
D3DXMatrixRotationX matTemp, RotateAngle * (pi / 180)
D3DXMatrixMultiply matWorld, matWorld, matTemp
D3DXMatrixIdentity matTemp
D3DXMatrixRotationZ matTemp, RotateAngle * (pi / 180)
D3DXMatrixMultiply matWorld, matWorld, matTemp
D3DDevice.SetTransform D3DTS_WORLD, matWorld

Zuerst erstellen wir zwei Matrizen, eine ist unsere Hauptmatrix, eine ist eine temporäre, weil wir mehr als eine Transformation machen, brauchen wir eine Matrix, um die Zwischenschritte zu speichern. Danach leeren wir unsere Hauptmatrix - das ist ein wichtiger Schritt, weil Fehler sich schnell vermehren werden, d.h. wenn die Matrix in jedem Frame verändern, ohne sie zurückzusetzen, dann wird schnell etwas sehr schnell schief gehen.

Nachdem wir die Matrix zurückgesetzt haben, können wir sie manipulieren. Hier ein paar möglich Transformationen:

'Normale Rotation
D3DXMatrixRotationX(Out As D3DMATRIX, angle As Single)
D3DXMatrixRotationY(Out As D3DMATRIX, angle As Single)
D3DXMatrixRotationZ(Out As D3DMATRIX, angle As Single)
'Rotation über eine benutzerdefinierte Achse
'Sie müssen die Achse über VAxis definieren
' FYI: X=[1,0,0] Y=[0,1,0] and Z=[0,0,1]

D3DXMatrixRotationAxis(MOut As D3DMATRIX, VAxis As _
  D3DVECTOR, angle As Single)
'Andere Transforms
'Die Funktion skaliert die Verticen um den angegebenen Wert

D3DXMatrixScaling(MOut As D3DMATRIX, _
  x As Single, y As Single, z As Single)
'Diese Funktion bewegt die Verticen um den angegebenen Wert

D3DXMatrixTranslation(MOut As D3DMATRIX, _
  x As Single, y As Single, z As Single)

'Es gibt andere Funktionen schauen Sie
'sich mal im VB-Objektbrowser an:
'DxVBLibA -> D3DXMATH_MATRIX

Noch was, wenn Sie Verticen rotieren - der Wert wird in Radianten angegeben, nicht in Grad. Wenn Sie mit Radianten glücklich sind, dann können Sie diese benutzen, wenn Sie allerding Grad angegeben wollen, dann können Sie diese Formel zum Umrechnen benutzen:

Grad * (PI / 180)
Dann kommen wir an den Punkt, an dem wir die Matrix unserer Device zuweisen. Das kann so oft geschehen, wie sie wollen; aber je weniger, desto besser. Nachdem die Matrix einmal zugewiesen ist, werden alle Verticen mit dieser transformiert - bis die nächste zugewiesen wird.

View Matrix:

Die View Matrix können Sie sich als Kamera vorstellen. Die Projection Matrix, kontrolliert die etwas komplizierteren Teile der "Kamera", die View Matrix hingegen werden Sie mehr brauchen, wenn Sie die Kamera versetzen wollen(wie es die meisten Spiele machen). Die View Matrix zu setzen ist extrem einfach, Sie müssen vorher aber ein bisschen überlegen - wenn nichts auf dem Bildschirm auftaucht, dann stehen die Chancen gut, dass Sie die Kamera falsch gesetzt haben.

Um die View Matrix zu ändern brauchen Sie diesen Code:

'/Der Funktion-Prototyp
D3DXMatrixLookAtLH(MOut As D3DMATRIX, VEye As _
  D3DVECTOR, VAt As D3DVECTOR, VUp As D3DVECTOR)

'Jetzt das Beispiel:
Dim matView As D3DMATRIX
Dim vecFrom As D3DVECTOR
Dim vecTo As D3DVECTOR
Dim vecUP As D3DVECTOR

  'Die Kamera ist an diesem Punkt in der 3D-Welt
vecFrom.X = 0
vecFrom.Y = 10
vecFrom.Z = 10

'Und schaut auf diesen Punkt
vecTo.X = 0
vecTo.Y = 0
vecTo.Z = 0

' Solange Sie nicht was besonders cleveres machen wollen
' Können Sie diese Werte für alles lassen.
vecUp.X = 0
vecUp.Y = 1
vecUp.Z = 0

'Jetzt erstellen wir die Matrix
D3DXMatrixLookAtLH matView, vecFrom, vecTo, vecUp
D3DDevice.SetTransform D3DTS_VIEW, matView

Projection Matrix:

Zuletzt kommen wir zur Projection Matrix; diese Matrix ist wird nicht so oft benutzt, wie die anderen, aber sie ist ungefähr gleich wichtig. Die Projection Matrix kontrolliert, wie eine Szene erscheint, wenn wir durch die Kamera schauen - sie können das Sichtfeld(Field of View) setzen(das nahste sichtbare Objekt und das entfernteste) und den Sichtwinkel. Wenn Sie nicht ein Spiel mit Zoom-Feature machen wollen, dann werden Sie diese Matrix nicht sehr oft verändern; normalerweise wird sie während der Initialisierung gesetzt und dann in Ruhe gelassen:

'Der Funktionprototyp:
D3DXMatrixPerspectiveFovLH( MOut As D3DMATRIX, _
fovy As Single, aspect As Single, zn As Single, zf As Single)
'Mout ist das Ergebnis
'zn ist die naheste Position für Polygonen -
'alles von hier bis zur Kamera wird nicht gerendert.
'zf ist die fernste Grenze - alles dahinter wird
'nichts gerendert.

'Jetzt erstellen wir die Matrix
D3DXMatrixPerspectiveFovLH matProj, pi / 4, 1, 0.1, 500
  'Jetzt setzen wir die Matrix für unserem Device
D3DDevice.SetTransform D3DTS_PROJECTION, matProj

Matrizen sind also nicht so schwer - Sie werden Sie für jede 3D-Szene die Sie rendern benutzen, deshalb werden Sie sich wohl schnell an sie gewöhnen. Eine letzte Sache, was ziemlich logisch ist: wenn World Matrizen Verticen transformieren, dann können Sie sie nicht mit transformierten Verticen benutzen.

Rendern  

Das Rendern unserer Verticen ist wieder keine richtige Änderung, nur ein paar neue Zeilen zum Anschauen. Also werde ich mich nicht lange darüber auslassen.

'Zuerst löschen wir den Inhalt unseres Device
D3DDevice.Clear 0, ByVal 0, D3DCLEAR_TARGET Or _
  D3DCLEAR_ZBUFFER, 0, 1#, 0

'Jetzt müssen wir unsere Verticen rendern.
D3DDevice.SetStreamSource 0, VBuffer, Len(Cube(0))
D3DDevice.DrawPrimitive D3DPT_TRIANGLELIST, 0, 12

Weil wir jetzt Tiefenbuffer benutzen, müssen wir diesen neben dem Renderziel auch löschen - wenn Sie das vergessen, dann werden schnell verrückte Dinge mit der Reihenfolge geschehen.

Zuletzt, wenn wir Vertex Buffer für unsere Geometry benutzen, dann müssen wir sie etwas anders rendern; wir müssen unserem Device sagen, welchen Vertex Buffer wir benutzen und wie groß ein Eintrag ist. Nachdem wir das getan haben können wir den normalen (und einfacheren) D3DDevice.DrawPrimative-Aufruf benutzen.

Voraussetzend, dass alles gut gegangen ist (es sollte), dann werden Sie so was wie hier sehen:


Abbildung 1: Ein Screenshot des Beispiels

Beispielprojekt zum Tutorial 

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.