OpenGL in Visual Basic - Formen und Farben
von Hans Henning Klein
Grundlagen
Nachdem wir mit viel Aufwand ein wenig beeindruckendes schwarzes Fenster erzeugt haben, kommen wir nun zu den ersten Formen und damit zu den Grundflächen, aus denen jede 3D-Welt besteht. Eigentlich besteht jede 3D-Welt nur aus dreieckigen Flächen; in der Grafikprogrammierung oft einfach als Polygone bezeichnet. Selbst die komplexen Welten von z.B. Unreal Tournament bestehen "nur" aus Tausenden von Dreiecken. Anhand diverser Daten der Vertices (Eckpunkte) eines Dreiecks, sowie der Beleuchtung, Textur und Oberflächeneigenschaften berechnet die Grafikengine für jedes Pixel dessen Farbe.
Bevor Sie jetzt das nackte Grauen packt, wir werden später lernen, dass OpenGL auch komfortable Möglichkeiten hat, komplexe Figuren darzustellen. Aber für den Anfang ist es wichtig, dass Sie den Umgang mit den einfachsten Grundformen einer 3D-Welt verstehen.
Um zu wissen, wie Grafiken in 3D dargestellt werden, sehen wir uns zuerst das Koordinatensystem an. Jeder Punkt (oder Eckpunkt einer Fläche) wir durch 3 Koordinaten definiert: X für waagerecht, Y für senkrecht und Z für die Tiefe. Der Mittelpunkt unserer 3D-Welt mit den Koordinaten 0,0,0 ist dabei in der Mitte des Bildschirms. Die Z-Koordinate wird von OpenGL umgerechnet, damit alle Objekte in der richtigen Reihenfolge auf dem flachen Bildschirm dargestellt werden.
Abbildung 1: Das (rechtshändige) Koordinatensystem von OpenGL
Formen
Wie bereits in der Einführung besprochen, werden alle Zeichenoperationen in der Endlos-Schleife erzeugt, in der das Programm läuft. Daher ändern wir in diesem Kapitel nur die Sub Main und zeichnen ein einfaches Dreieck und ein einfaches Viereck in unser Fenster:
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 '--- neuer Code seit der Einführung --- 'ab hier zeichnen wir ein Dreieck in unser Fenster glTranslatef -1.5, 0#, -6# 'Setzt den neuen Zeichenpunkt. Ab dieser Koordinate werden nun alle Zeichenoperationen berechnet 'Das heißt wir verschieben den Punkt um 1,5 Einheiten nach Links und 6 Einheiten "in den Bildschirm" glBegin bmTriangles 'Anfang eines Dreiecks glVertex3f 0#, 1#, 0# 'obere Ecke glVertex3f -1#, -1#, 0# 'untere linke Ecke glVertex3f 1#, -1#, 0# 'untere rechte Ecke glEnd 'Ende des Dreiecks glTranslatef 3#, 0#, 0# 'Zeichenpunkt um 3 Einheiten nach rechts verschieben glBegin bmQuads 'Anfang eines Vierecks glVertex3f -1#, 1#, 0# 'linke obere Ecke glVertex3f 1#, 1#, 0# 'rechte obere Ecke glVertex3f 1#, -1#, 0# 'untere rechte Ecke glVertex3f -1#, -1#, 0# 'untere linke Ecke glEnd 'Ende des Vierecks '--- Ende neuer Code seit der Einführung 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 1: Sub Main für einfache Polygone
Wenn Sie das Fenster vergrößern, werden Sie feststellen, dass die gezeichneten Formen die Größenänderung mitmachen.
Das sind nun keine einfachen Grafiken mehr sondern Objekte in einer 3D-Welt, deren Darstellung von ihrer relativen Größe in dieser Welt und dem Abstand der Kamera (des Beobachters) abhängt.
Farben
Kommen wir nun zu den Farben. Die Farben werden im RGB-Format angegeben. Im Gegensatz zu VB sind die Werte nicht von 0 bis 255 sondern von 0 bis 1 definiert. OpenGL verwendet immer die zuletzt definierte Farbe als Zeichenfarbe. Daher müssen wir für ein einfarbiges Objekt die Farbe auch nur einmal setzen.
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 '--- neuer Code seit der Einführung --- 'ab hier zeichnen wir ein Dreieck in unser Fenster glTranslatef -1.5, 0#, -6# 'Setzt den neuen Zeichenpunkt. Ab dieser Koordinate werden nun alle Zeichenoperationen berechnet 'Das heißt, wir verschieben den Punkt um 1,5 Einheiten nach Links und 6 Einheiten "in den Bildschirm" glBegin bmTriangles 'Anfang eines Dreiecks glColor3f 1#, 0#, 0# 'setzt die Zeichenfarbe auf Rot glVertex3f 0#, 1#, 0# 'obere Ecke glColor3f 0#, 1#, 0# 'setzt die Zeichenfarbe auf Grün glVertex3f -1#, -1#, 0# 'untere linke Ecke glColor3f 0#, 0#, 1# 'setzt die Zeichenfarbe auf Blau glVertex3f 1#, -1#, 0# 'untere rechte Ecke glEnd 'Ende des Dreiecks glTranslatef 3#, 0#, 0# 'Zeichenpunkt um 3 Einheiten nach rechts verschieben glColor3f 0.7, 0.7, 1# 'setzt die Zeichenfarbe einmal auf Hellblau für alle Ecken glBegin bmQuads 'Anfang eines Vierecks glVertex3f -1#, 1#, 0# 'linke obere Ecke glVertex3f 1#, 1#, 0# 'rechte obere Ecke glVertex3f 1#, -1#, 0# 'untere rechte Ecke glVertex3f -1#, -1#, 0# 'untere linke Ecke glEnd 'Ende des Vierecks '--- Ende neuer Code seit der Einführung 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 2: Sub Main für farbige Polygone
Abbildung 2: Die Arbeit trägt erste Früchte...
Es geht weiter
Manche werden sich jetzt zu Recht fragen, ob später jedes von mehreren hundert Objekten so in der Sub Main hinterlegt werden muss. Dem ist natürlich nicht so, aber zum besseren Verständnis lassen wir das jetzt mal noch so.
Im 2. Kapitel beginnen wir dann endlich mit echtem 3D, drehen Flächen im Raum und erstellen erste 3D-Objekte.
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.