Die Community zu .NET und Classic VB.
Menü

OpenGL in Visual Basic - Einführung

 von 

Einführung 

Willkommen zum ersten Tutorial über OpenGL-Grafiken. Es gibt vermutlich nur einen guten Grund, warum Sie hier sind: Sie beherrschen einigermaßen VB und schauen voller Neid auf die 3D-Anwendungen, welche in C++ programmiert werden. Nun, dann sind Sie hier genau richtig, denn mittels OpenGL kann man auch in VB beeindruckende Effekte realisieren. Bevor Sie jetzt aber damit beginnen, eine 3D-Engine für Doom8 zu planen, möchte ich auch hier die Grenzen aufweisen... Es ist mittels OpenGL durchaus möglich, optisch anspruchsvolle 3D-Applikationen zu entwickeln, welche auch vor Effekten wie Explosionen oder Nebel nicht kapitulieren, aber die Anzahl der darstellbaren Objekte ist in VB durch die schlechte Laufzeit begrenzt. Dieses Tutorial richtet sich daher eher an Entwickler, deren Ambitionen in der Verbesserung alltäglich verwendeter Programme liegen (Einen guten 3D-Explorer gibt es bis heute meines Wissens nicht...), oder deren Spiele eine gewisse grafische Komplexität nicht übersteigen. Letztere müssen nicht zwangsweise primitiv sein, aber es sollten eher Rollenspiele (RPG) statt Ego-Shooter sein.

Warum nun OpenGL? Nun, zum einen ist es einmal nicht von unserem Lieblingsmonopolisten, zum anderen ist es eine mit DirectX vergleichbare, wenn nicht sogar leistungsstärkere Sammlung von Klassen, die relativ leicht zu beherrschen sind.

Was sollten Sie mitbringen? Um diesem Tutorial zu folgen sollten Sie in der Lage sein Standard-Exe Programme in VB zu entwickeln. Sie sollten bereits ein paar einfache Projekte erstellt haben und gut dokumentierten Quellcode lesen können. Ich möchte damit Anfänger nicht unbedingt ausschließen, aber es wird im Zuge des Tutorials nicht auf Dinge eingegangen, die in VB selbstverständlich sind.


Abbildung 1: Viel Aufwand für ein schwarzes Fenster. Doch es ist die Grundlage für alles Folgende.

Der Anfang  

Der erste Teil, den wir hier lernen, ist ein Fenster für unsere OpenGL-Programme zu erzeugen. Obwohl Sie später vermutlich diesen Teil als Modul speichern und in vielen Projekten einfach einbinden werden, sollten Sie sich trotzdem die Zeit nehmen, diesen Bereich zu verstehen. Das Studium der Grundlagen mag langweilig sein, aber es erspart Ihnen später stundenlanges Rumprobieren oder Suchen in diesem Tutorial.

Ein OpenGL-Projekt erstellen

Ein OpenGL-Projekt erstellen: Starten Sie ein neues Projekt, vorzugsweise als Standard-Exe. Öffnen Sie das Projekt-Menü und klicken Sie auf Verweise. Klicken Sie auf Durchsuchen und fügen Sie die vbogl.tlb hinzu. Diese Datei stellt die VB OpenGL API 1.2 zur Verfügung und ist in den Beispielprojekten dieses Tutorials enthalten. Öffnen Sie nun über das Menü Projekt die Projekt-Eigenschaften und stellen Sie als Start-Objekt Sub Main ein. Fügen Sie zu Ihrem Projekt ein Modul hinzu und erstellen Sie in diesem Modul eine neue Prozedur Main.

Das wird vielen jetzt seltsam erscheinen, aber eine OpenGL-Anwendung hat mit dem klassischen ereignisorientierten Programmablauf in VB nichts zu tun. Vielmehr läuft eine OpenGL-Anwendung in einer Endlosschleife. Bei jedem Durchlauf wird die Ausgabe gelöscht und neu gezeichnet.

Nur ein schwarzes Fenster  

Der Aufwand, um nur ein schwarzes Fenster zu erzeugen, wird Ihnen im Moment unglaublich groß erscheinen. Schließlich geht das in VB um einiges einfacher. Aber ein schwarzes Fenster ist in OpenGL eigentlich schon eine komplette 3D-Welt, auch wenn wir zu Anfang noch kein Objekt darstellen.

Zuerst benötigen wir noch zwei Variablen:

Public PrgRun As Boolean 'Flag = Programm läuft
Private hrc As Long      'Handle für den OpenGL Gerätekontext

Listing 1: Globale Variablen

Beginnen wir nun mit einer Prozedur, die alle Arbeiten zur Erstellung eines OpenGL-Fensters erledigt. Fügen Sie die Prozedur CreateGLWindow zu Ihrem Modul hinzu:

Public Function CreateGLWindow(frm As Form, Width As Integer, Height As Integer, Bits As Integer) As Boolean
   Dim pfd As PIXELFORMATDESCRIPTOR ' pfd erklärt Windows, wie das Fenster beschaffen sein soll
   Dim PixelFormat As GLuint ' enthält das Ergebnis vom Versuch, ein Fenster mit den gegebenen Parametern zu erstellen
 
   pfd.cColorBits = Bits 'Farbtiefe
   pfd.cDepthBits = 16 '16 Bit Tiefenpuffer
   'Der Tiefenpuffer enthält die Entfernung eines Pixels zur Kamera (Betrachter).
   'Er verhindert, daß Objekte im Hintergrund beim Zeichnen Objekte im Vordergund überlagern.
   pfd.dwFlags = PFD_DRAW_TO_WINDOW Or PFD_SUPPORT_OPENGL Or PFD_DOUBLEBUFFER
   'PFD_DRAW_TO_WINDOW = das Format muss als Fenster sichtbar sein können
   'PFD_SUPPORT_OPENGL = das Format muss OpenGL unterstützen
   'PFD_DOUBLEBUFFER = das Format muss Double Buffering unterstützen
   pfd.iLayerType = PFD_MAIN_PLANE 'Die Hauptebene auf der gezeichnt wird.
   pfd.iPixelType = PFD_TYPE_RGBA 'Pixel werden im RGBA Modus dargestellt.
   'RGB ist mit VB identisch. Für A wird ein Alpha-Wert für die Transparenz übergeben
   pfd.nSize = Len(pfd) 'Größe der Struktur sollte natürlich stimmen
   pfd.nVersion = 1 'Versionsnummer
 
   PixelFormat = ChoosePixelFormat(frm.hDC, pfd) 'Prüfen, ob das oben beschriebene Pixelformat verfügbar ist
   If PixelFormat <> 0 Then
      'Das Format ist verfügbar.
      If SetPixelFormat(frm.hDC, PixelFormat, pfd) <> 0 Then
         'Einrichten des Pixelformates war erfolgreich
         hrc = wglCreateContext(frm.hDC)
         If hrc <> 0 Then
            'ein Rendering Kontext wurde erstellt
            If wglMakeCurrent(frm.hDC, hrc) <> 0 Then
               'Der Kontext wurde aktiviert
               frm.Show 'Fenster anzeigen
               glShadeModel smSmooth 'schaltet schöne Farbübergange ein
               glClearColor 0#, 0#, 0#, 0# 'schwarzer Hintergrund
               glClearDepth 1# 'Tiefenpuffer zurücksetzten (später mehr)
               glEnable glcDepthTest 'Aktivierung des Tiefentests (später mehr)
               glDepthFunc cfLEqual 'Typ des Tiefentests (später mehr)
               glHint htPerspectiveCorrectionHint, hmNicest 'Art der Perspektiven-Ansicht
               'hmNicest = beste Ansicht / hmFastest = schnellste Darstellung
               CreateGLWindow = True
            End If
         End If
      End If
   End If
End Function

Listing 2: CreateGLWindow

Als nächstes benötigen wir noch eine Prozedur, die OpenGL mitteilt, ob sich die Fenstergröße geändert hat. Fügen Sie die Prozedur ReSizeGLScene zu Ihrem Modul hinzu:

Public Sub ReSizeGLScene(ByVal Width As GLsizei, ByVal Height As GLsizei)
   'Anpassen der Größe und Initialisierung des OpenGL-Fensters
   If Height = 0 Then 'Die Fensterhöhe muss größer 0 sein
       Height = 1 'sonst kommt es zu einem "Division by Zero"-Fehler
   End If
   glViewport 0, 0, Width, Height 'leeren des aktuellen Viewports
   glMatrixMode mmProjection 'Auswahl der Projektionsmatrix
   glLoadIdentity 'setzt die aktuelle Modell-Matrix zurück
 
   gluPerspective 45#, Width / Height, 0.1, 100# 'Berechnung des aktuellen Seitenverhältnisses des Fensters
 
   glMatrixMode mmModelView 'Auswahl der Modelview Projektionsmatrix
   glLoadIdentity 'setzt die aktuelle Modell-Matrix zurück
End Sub

Listing 3: ReSizeGLScene

Damit diese auch entsprechend aufgerufen wird, setzen wir einen Call in das Resize-Ereignis der Form:

Private Sub Form_Resize()
   ReSizeGLScene ScaleWidth, ScaleHeight
End Sub

Listing 4: Form_Resize

Was wir jetzt noch benötigen, ist die Sub Main. In dieser Prozedur läuft die oben angesprochene Endlosschleife:

Public Sub Main()
   Dim frm As Form
 
   PrgRun = True 'Flag = das Programm läuft
   Set frm = New Form1 'Fenster für OpenGL-Ausgabe
   frm.ScaleMode = vbPixels 'das Fenster muss zwingend in Pixel bemessen werden
 
   If CreateGLWindow(frm, 640, 480, 16) Then 'Fenster initialisieren
      Do 'Endlosschleife, in der das Fenster laufend gelöscht und neu aufgebaut wird.
         'Die Laufzeit dieser Schleife ist ausschlaggebend, wieviele Objekt gezeichnet werden können
         glClear clrColorBufferBit Or clrDepthBufferBit ' löscht das Fenster und den Tiefenpuffer
         glLoadIdentity 'setzt die aktuelle Modell-Matrix zurück
         SwapBuffers (frm.hDC) 'Puffer tauschen (Double Buffering)
         DoEvents
      Loop While PrgRun 'Programm nur beenden, wenn PrgRun = False
      'PrgRun ist Global definiert und wird im KeyDown-Ereignis von Form1 bei drücken von Escape gesetzt.
      'alles freigeben und Programm beenden
      If hrc <> 0 Then 'hatten wir einen Gerätekontext für OpenGL?
         wglMakeCurrent 0, 0 'Freigeben des Gerätekontexts
         wglDeleteContext (hrc) 'Freigeben des Renderingkontexts
      End If
      Unload frm
      Set frm = Nothing
      End
   End If
End Sub

Listing 5: Sub Main

Um das Programm zu beenden, setzen wir im KeyDown-Event der Form PrgRun auf False falls die ESC-Taste gedrückt wird:

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
   If KeyCode = vbKeyEscape Then
      PrgRun = False
   End If
End Sub

Listing 6: Form_KeyDown

Das Ende vom Anfang  

Das hat alles geklappt und Sie haben ein schwarzes Fenster erzeugt? Herzlichen Glückwunsch und willkommen in der 3D-Welt. Im 1. Kapitel lernen wir, wie einfache Flächen dargestellt werden.

Beispielprojekt  

Beispielprojekt zum Tutorial [193314 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.