Dieses Tutorial richtet sich an erfahrene VisualBasic-Entwickler, die mit der 3D-Grafik-Programmierung interessantes Neuland entdecken wollen. Für das volle Verständnis des Beispielcodes werden jedoch Grundsätze der Vektormathematik benötigt. 1. Vorbereitungen
Direct3D: Das Ziel: Doch beginnen wir ohne weitere Umschweife... 2. Deklarationen Zunächst müssen wir ein paar Objeklt-Variablen deklarieren. Die Deklaration erfolgt hierbei in einem Modul. Fügen Sie nachfolgenden Code in das Modul ein, den Sie sich auch sorgfältig durchlesen sollten! Option Base 0 Option Explicit ' Deklaration aller benötigten Objekt-Variablen ' Das ist unser globales DirectX8 Objekt Public myDX8 As New DirectX8 ' Dies ist unser Direct3D-Objekt Public myD3D8 As Direct3D8 ' Das D3DDevice ist sozusagen das Objekt, ' das die 3DGrafik zeichnet und berechnet Public D3DDevice As Direct3DDevice8 Wenn wir Direct3D benutzen, müssen wir immer auch sicherstellen, dass der PC, auf dem das Programm ausgeführt wird, alle benötigten Features unterstützt. Andernfalls kann es zu schweren Fehlern kommen. Deshalb sollte man zunächst ermitteln, was die Grafikkarte des PCs leisten kann und was nicht, was man sich natürlich irgendwo merken (zwischenspeichern) muss. ' Hier legen wir fest, ob die Anwendung z.B. ' Fullscreen benutzen soll Public D3DPP As D3DPRESENT_PARAMETERS Public DispMode As D3DDISPLAYMODE ' In dieser Variable speichern wir, ob ein ' 3D-Beschleuniger vorhanden ist Public D3D_HwOrSw As Long ' Das soll unsere Fenstergröße sein Public Const ScreenWidth As Long = 640 Public Const ScreenHeight As Long = 480 ' Dies hier sind Matrizen für den 3D-Raum. Man benötigt ' Matrizen, um mathematische Operationen im 3D-Raum ' möglichst effizient umzusetzen. Public matWorld As D3DMATRIX Public matView As D3DMATRIX Public matProj As D3DMATRIX ' Mit dieser Matrix können wir bequem die Szene ' rotieren, so dass das Ganze interessanter aussieht Public matRotation As D3DMATRIX ' Die aktuelle Rotation Public Rotation As Double ' Pi brauch man auch oft für Berechnungen Public Const Pi = 3.14159265358979 Natürlich brauchen wir auch etwas zum Darstellen. Das speichern wir in diesem Typ: Public Type D3DColorVertex x As Single y As Single z As Single color As Long End Type ' Mit dieser Konstanten sagen wir später dem Device wie ' es unseren selbst definierten Typ zu verstehen hat. Public Const D3DFVF_COLORVERTEX = D3DFVF_XYZ Or _ D3DFVF_DIFFUSE ' Und davon nehmen wir 12 Stück Public Triangles(11) As D3DColorVertex ' Wird die Anwendung noch ausgeführt? Public bRunning As Boolean 3. Die Sub Main Wenn wir es mit Direct3D zu haben, brauchen wir eigentlich keine Forms oder Steuerelemente. Deshalb sollte man auch keine Form als Start-Objekt definieren, sondern stattdesse die Sub Main. In der DirectX-Programmierung hat sich das eben so eingebürgert Die "Sub Main" sollte gut gegliedert und nicht zu umfangreich werden. Folgender Code kommt ebenfalls in das Modul: Public Sub Main() ' Anzeigen unserer Form im Vollbild-Modus With Form1 .Show .Width = ScreenWidth * Screen.TwipsPerPixelX .Height = ScreenHeight * Screen.TwipsPerPixelY End With ' Start der Initialisierung ' Wenn die Initialisierung von Direct3D fehlschlägt, ' soll mit dem Programm gar nicht erst fortgefahren ' werden bRunning = InitD3D ' Hier regeln wir alle sonstigen Dinge die noch zu ' erledigen sind, bevor es dann los gehen kann If bRunning Then InitSettings ' Danach initialisieren wir unsere Geometrie, die wir ' rendern (zeichnen) wollen If bRunning Then InitTriangles ' Direct3D Anwendungen müssen in einem Loop ausgeführt ' werden, in dem die Szene immer wieder neu gezeichnet ' wird. Diesen Loop nennen wir MainLoop Mainloop ' Wenn man mit DirectX arbeitet ist es immer wichtig ' sämtliche Objekte wieder freizugeben, da sie einem ' onst den Speicher "vollmüllen" TerminateD3D ' Und jetzt noch die Form entladen Unload Form1 End Sub Nachdem Sie den Code eingefügt haben, müssen Sie noch die Sub Main als Startobjekt definieren. Öffnen Sie hierzu das Projekt-Eigenschaften Dialogfenster (Menü Projekt - Eigenschaften von...), klicken auf das Register "Projekt" und wählen dort als Startobjekt "Sub Main" aus. Nun wollen wir uns mit den einzelnen Funktionen beschäftigen... 4. Die Initialisierung der benötigten Objekte Für die Initialisierung erstellen wir eine eigene Funktion: Init3D3. Erfolgt die Initialisierung erfolgreich bekommen wir ein Device. Ein Device kann man mit einer PictureBox vergleichen: es enthalt die Funktionen und Werte, über die man das Zeichnen auf innerhalb des Device steuern kann. Die Initialisierungs-Funktion kommt ebenfalls wieder ins Modul. Schauen Sie sich den Code genau an, um zu verstehen, was alles wie initialisier werden sollte. Public Function InitD3D() As Boolean ' Wichtig! Fehlerbehandlung aktivieren On Error Resume Next ' Zuerst müssen wir unser Direct3D-Objekt aus dem ' DirectX-Objekt erstellen Set myD3D8 = myDX8.Direct3DCreate ' Nun ermitteln wir noch, welchen Bildschirmmodus die ' Grafikkarte momentan hat... myD3D8.GetAdapterDisplayMode D3DADAPTER_DEFAULT, _ DispMode ' ...und setzen anschließend unsere Wunschauflösung DispMode.Width = ScreenHeight DispMode.Height = ScreenHeight ' Dann schauen wir, ob die Grafikkarte ' 3D-Beschleunigung unterstützt If myD3D8.CheckDeviceType(D3DADAPTER_DEFAULT, _ D3DDEVTYPE_HAL, DispMode.Format, _ DispMode.Format, 1) = D3D_OK Then ' Hardwarebeschleunigung wird unterstützt D3D_HwOrSw = D3DDEVTYPE_HAL Else ' Kein Harwarebeschleunigung: Der Prozessor muss ' alles selbst machen D3D_HwOrSw = D3DDEVTYPE_REF End If With D3DPP ' Diesen Teil sollten Sie einfach einmal ' schlucken :-) .BackBufferCount = 1 .EnableAutoDepthStencil = 0 .SwapEffect = D3DSWAPEFFECT_FLIP .BackBufferFormat = DispMode.Format .AutoDepthStencilFormat = D3DFMT_D16 .EnableAutoDepthStencil = 1 ' Wir wollen Fenster und nicht Fullscreen .Windowed = 1 ' Hiermit legen wir fest, wie groß das Farbspektrum ' unseres Fenster sein soll. ' Da wir kein Fullscreen möchtenm, wird automatisch ' die Farbtiefe des Desktops genommmen .BackBufferFormat = DispMode.Format ' Die Fenstergröße nehmen wir auch für den BackBuffer. ' Auf dem BackBuffer kann z.B. Anisotrope filterung ' vorgenommen werden, bevor die Szene gerendert wird .BackBufferWidth = ScreenWidth .BackBufferHeight = ScreenHeight ' Dann teilen wir dem Device noch mit, in welchem ' Fenster es 'Rendern' (=zeichnen) soll. ' Hierzu nehmen wir einfach die hWnd-Eigenschaft ' unserer Form1 .hDeviceWindow = Form1.hWnd End With ' Nun erstellen wie unser Device. ' Wir benutzen Softwware-Vertex-Processing, weil nur ' neuere GeForce-Karten Harware-Vertex-Processing ' unterstützen. Das könnte man zwar auch abfragen, ' aber für den Anfang reicht das erst mal ;) Set D3DDevice = myD3D8.CreateDevice(0, D3D_HwOrSw, _ Form1.hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, _ D3DPP) ' So, dann schauen wir doch mal, ob es ' funktioniert hat If D3DDevice Is Nothing Then ' Das Device ist leer, also haben wir was ' falsch gemacht InitD3D = False Else ' Das Device ist da! InitD3D = True End If End Function 5. Geometrie und Matrizen Damit es was zu sehen gibt, brauchen wir Objekte. Objekte beliebiger Form kann man aus Dreicken (=Triangles) zusammenbauen. Ein Dreieck (auch 'Polygon') kann man wiederum aus 3 Punkten im Raum definieren. Genau das tun wir jetzt: vier Dreicke aus 12 Punkten basteln. Wenn man diesen Punkten mehr als nur Koordinaten mitgibt z.B. Farbe etc., nennt man sie VERTEX. Diesen Code bitte auch in das Modul kopieren: Public Sub InitTriangles() Triangles(0) = MakeColorVertex(10, 10, 10, _ D3DColorARGB(0, 255, 0, 0)) Triangles(1) = MakeColorVertex(10, -10, 0, _ D3DColorARGB(0, 0, 255, 0)) Triangles(2) = MakeColorVertex(10, 10, 0, _ D3DColorARGB(0, 255, 255, 0)) Triangles(3) = MakeColorVertex(-10, -10, 10, _ D3DColorARGB(0, 255, 0, 0)) Triangles(4) = MakeColorVertex(-10, 10, 0, _ D3DColorARGB(0, 0, 0, 255)) Triangles(5) = MakeColorVertex(-10, 10, 10, _ D3DColorARGB(0, 0, 255, 255)) Triangles(6) = MakeColorVertex(10, 15, 10, _ D3DColorARGB(0, 255, 255, 0)) Triangles(7) = MakeColorVertex(0, 15, 0, _ D3DColorARGB(0, 255, 0, 255)) Triangles(8) = MakeColorVertex(-10, 15, 10, _ D3DColorARGB(0, 255, 0, 255)) Triangles(9) = MakeColorVertex(-5, -15, 10, _ D3DColorARGB(0, 0, 255, 255)) Triangles(10) = MakeColorVertex(0, -15, 0, _ D3DColorARGB(0, 0, 255, 0)) Triangles(11) = MakeColorVertex(10, -15, 10, _ D3DColorARGB(0, 255, 0, 255)) End Sub ' eine kleine Hilfs-Funktion Public Function MakeVector(ByVal x As Single, _ ByVal y As Single, _ ByVal z As Single) As D3DVECTOR With MakeVector .x = x .y = y .z = z End With End Function ' noch eine kleine Hilfsfunktion Public Function MakeColorVertex(ByVal x As Single, _ ByVal y As Single, _ ByVal z As Single, _ ByVal c As Long) As D3DColorVertex With MakeColorVertex .x = x .y = y .z = z .color = c End With End Function Somit habe wir 4 Triangles erstellt. Aus den ganzen Zahlen dort müssen Sie nicht schlau werden. Es genügt, wenn Sie verstanden haben, wie man aus 3 Eckpunkten ein Dreieck bastelt. Damit alles einwandfrei funktioniert müssen wir aber noch definieren, wie von wo aus wir uns diese 3D-Welt anschauen. Dazu benutzt man verschiedene Matrizen, die Ort des "Auges", Blickwinkel, Verzerrungen und Rotation festlegen. Außerdem muss man dem Device auch noch mitteilen, wie es unsere Geomtrie-Daten zu verstehen hat. Kopieren Sie folgenden Code wiederum in das Modul: Public Sub InitSettings() ' Das hier sollte Sie erst einmal auch nicht kümmern. ' Hier wird mit Hilfe einer Matrix festgelegt, wie ' die einzelnen Objekte zu rendern sind. D3DXMatrixIdentity matWorld D3DDevice.SetTransform D3DTS_WORLD, matWorld ' Diese Matrix kann man als Kamera betrachten, mit ' der sich das Sichtfeld modifizieren lässt. D3DXMatrixLookAtLH matView, MakeVector(40, 40, 40), _ MakeVector(0, 0, 0), MakeVector(0, 1, 0) D3DDevice.SetTransform D3DTS_VIEW, matView ' Mit der Projektion-Matrix legen wir Sichtweite und ' Sichtwinkel fest. D3DXMatrixPerspectiveFovLH matProj, Pi / 4, 1, 0.01, 200 D3DDevice.SetTransform D3DTS_PROJECTION, matProj ' Jetzt teilen wir dem Device noch mit, welches ' Art Vertex wir haben D3DDevice.SetVertexShader D3DFVF_COLORVERTEX ' Und noch ein paar Einstellungen D3DDevice.SetRenderState D3DRS_ZENABLE, 1 D3DDevice.SetRenderState D3DRS_LIGHTING, 0 D3DDevice.SetRenderState D3DRS_FILLMODE, D3DFILL_SOLID D3DDevice.SetRenderState D3DRS_CULLMODE, D3DCULL_NONE End Sub 6. Die Haupt-Schleife Die Hauptschleife enthält alle sich ständig wiederholenden Vorgänge. Dazu gehört:
Nachfolgenden Code bitte auch in das Modul einfügen: Public Sub Mainloop() ' Der MainLoop läuft solange wie wir die ' bRunning-Variable auf 'true' lassen Do While bRunning ' Das vorher Gezeichnete löschen, indem wir es mit ' grauer Farbe übermalen D3DDevice.Clear 0, ByVal 0, D3DCLEAR_TARGET Or _ D3DCLEAR_ZBUFFER, &H333333, 1#, 0 ' Dem Device sagen, dass das "rendern gleich ' beginnt" D3DDevice.BeginScene ' Und nun lassen wir das ganze noch rotieren Rotation = Rotation + 0.05 D3DXMatrixIdentity matWorld D3DXMatrixRotationY matRotation, Rotation * Pi / 180 D3DXMatrixMultiply matWorld, matWorld, matRotation D3DXMatrixRotationX matRotation, Rotation * 1.5 * Pi / 180 D3DXMatrixMultiply matWorld, matWorld, matRotation D3DXMatrixRotationZ matRotation, Rotation * 2 * Pi / 180 D3DXMatrixMultiply matWorld, matWorld, matRotation D3DDevice.SetTransform D3DTS_WORLD, matWorld ' Hier "rendern" wir unsere Szene D3DDevice.DrawPrimitiveUP D3DPT_TRIANGLELIST, 4, _ Triangles(0), Len(Triangles(0)) ' Rendern beendet D3DDevice.EndScene ' Und das Ganze "präsentieren" D3DDevice.Present ByVal 0, ByVal 0, 0, ByVal 0 ' Jeder, der schon mal einen Loop ohne Beendingung ' Beding gebastelt hat, weiß, dass man ein ' Doevents braucht, um noch Eingaben in seinen ' PC machen zu können DoEvents Loop End Sub 7. Beenden einer Direct3D Applikation Wie bereits erwähnt sollten alle erstellten Objekte bei Direct3D-Anwendungen zerstört werden, wenn die Aplikation beendet wird. Dies wird mit wachsender Geometrie auch immer wichtiger! Erledigt wird das auf folgende Weise. Bitte in das Modul einfügen: Public Sub TerminateD3D() ' Alle Objekte zerstören Set D3DDevice = Nothing Set myD3D8 = Nothing Set myDX8 = Nothing End Sub Nun haben wir ja einen Endlos-Loop namens MainLoop gebastelt. Da es aber im normalerweise gewünscht ist die Anwednung zu einem beliebigen Zeitpunkt beenden zu können, halten wir uns diese Möglcihkeit offen, indem wir einfach auf ein Mausklick oder Tastendruck-Ereignis die "bRunning"-Variable auf "False" setzen. Fügen sie bitte folgenden Code in die Form1 ein: Private Sub Form_Click() ' bei Mausklick soll die Anwendung beendet werden bRunning = False End Sub Private Sub Form_KeyDown(KeyCode As Integer, _ Shift As Integer) ' Auf Tastendruck soll man auch beenden können bRunning = False End Sub Private Sub Form_Unload(Cancel As Integer) ' Sicherzustellen, dass TerminateD3D aufgerufen ' wird BEVOR wir die Anwendung beenden If bRunning Then bRunning = False ' Entladen abbrechen Cancel = 1 End If End Sub Wenn Sie dieses Projekt jetzt ausführen, dann sollten sie 4 bunt-rotierende Dreiecke in einem dunkelgrauem Fenster sehen. Wenn alles geklappt hat, dann können Sie sich jetzt daran machen Schritt für Schritt die Welt von Direct3D zu erforschen. Bei Fragen zu diesem Workshop oder auch allgemeinen Fragen zur DirectX-Programmierung wenden Sie sich bitte an direkt an unser Dieser Workshop wurde bereits 18.130 mal aufgerufen.
Anzeige
![]() ![]() ![]() Ein absolutes Muss - Geballtes Wissen aus mehr als 8 Jahren vb@rchiv! - nahezu alle Tipps & Tricks und Workshops mit Beispielprojekten - Symbol-Galerie mit mehr als 3.200 Icons im modernen Look Weitere Infos - 4 Entwickler-Vollversionen (u.a. sevFTP für .NET), Online-Update-Funktion u.v.m. |
sevISDN 1.0 ![]() Überwachung aller eingehender Anrufe! Die DLL erkennt alle über die CAPI-Schnittstelle eingehenden Anrufe und teilt Ihnen sogar mit, aus welchem Ortsbereich der Anruf stammt. Weitere Highlights: Online-Rufident, Erkennung der Anrufbehandlung u.v.m. Tipp des Monats ![]() Manfred Bohn IndexOf für mehrdimensionale Arrays Die generische Funktion "IndexOf" ermittelt das erste Auftreten eines bestimmten Wertes in einem n-dimensionalen Array sevOutBar 4.0 ![]() Vertikale Menüleisten á la Outlook Erstellen von Outlook ähnlichen Benutzer- interfaces - mit beliebig vielen Gruppen und Symboleinträgen. Moderner OfficeXP-Style mit Farbverläufen, Balloon-Tips, u.v.m. |
|||||||||||||
Microsoft, Windows und Visual Basic sind entweder eingetragene Marken oder Marken der Microsoft Corporation in den USA und/oder anderen Ländern. Weitere auf dieser Homepage aufgeführten Produkt- und Firmennamen können geschützte Marken ihrer jeweiligen Inhaber sein. |