Die Community zu .NET und Classic VB.
Menü

OpenGL in Visual Basic - Displaylisten

 von 

Grundlagen 

Willkommen im Kapitel mit dem eingebauten Turbo. Bisher haben wir uns bei der Erarbeitung der Grundlagen wenig um Laufzeit oder gar deren Optimierung gekümmert. Das wird sich jetzt ändern. OpenGL bietet uns dazu ein schönes Werkzeug, genannt Displaylisten. Was sind nun Displaylisten?
Displaylisten sind eine Möglichkeit, eine Szene vorab zu berechnen und später einfach nur darzustellen.
In der Praxis läuft das so ab: Mit dem Erstellen einer Displayliste wird diese direkt an die Grafikkarte gesendet, dort vom Treiber so weit wie möglich optimiert und dann im lokalen Grafikkartenspeicher abgelegt. Wollen wir diese Informationen nun darstellen können diese einfach aus dem lokalen Speicher entnommen und gerendert werden. Mit der bisher von uns praktizierten Methode werden die Daten erst vom Hauptspeicher des Computers über den langsamen Bus zur Grafikkarte gesendet.

Ein kleines (theoretisches) Rechenbeispiel soll das verdeutlichen:
Der AGP-Bus zur Grafikkarte schafft im 8fach Modus etwa 2 GByte Daten je Sekunde. Moderne Grafikkarten haben ein Speicherinterface mit dem mehr als 20 GByte Daten je Sekunde aus dem lokalen Grafikkartenspeicher gelesen werden können. Das ergibt eine (theoretische) Steigerung auf die 10fache Geschwindigkeit. Diese Werte sind natürlich in der Realität nicht zu erreichen, aber Steigerungen von bis zu 100% sind durchaus möglich.

Gerade bei der Entwicklung von OpenGL-Anwendungen mit Visual Basic, welches selbst eher mäßig schnell ist, können Displaylisten zu einem enormen Zuwachs an Geschwindigkeit führen.
Natürlich hat das Ganze einen Pferdefuß - wär ja sonst zu schön gewesen. Displaylisten belegen relativ viel Platz und das auf dem internen Speicher der Grafikkarte. Sobald dieser nicht mehr ausreicht werden die Listen eben dennoch wieder im Hauptspeicher abgelegt und dann ist Schluss mit Tempo. Daher sollten Sie bei umfangreichen Projekten die Verwendung von Displaylisten genau planen und keinesfalls alles darin unterbringen.

Anmerkung: Bitte beachten Sie, dass dieser Code unter Umständen Probleme mit bestimmten Versionen von ATI-Grafikkartentreibern verursachen kann. Sollten Sie ebenfalls ein Problem feststellen, bitten wir um eine entsprechende Mitteilung mit Fehlermeldung, Grafikkarte und Treiberversion.


Abbildung 1: Mit Displaylisten lässt sich das Programm beschleunigen.

Praxis  

Dieses Beispiel basiert auf Kapitel 7 - Dynamische 3D-Welten und liest die Daten einer Kugel ein.

Public Function CreateGLWindow(frm As Form, Width As Integer, Height As Integer, Bits As Integer) As Boolean
'...
   LoadWorld App.Path & "\Kugel.txt" 'einlesen der Welt-Daten
   Call GenerateLists 'Displaylisten erstellen
'...
End Function

Listing 1: CreateGLWindow

Die Verwendung von Displaylisten ist denkbar einfach und benötigt nur wenige Anweisungen:

Public Sub GenerateLists()
   DisplayLists(0) = glGenLists(1) 'Zeiger auf eine neue Displayliste
   glNewList DisplayLists(0), lstCompile 'Neue Displayliste beginnen.
   'Der Parameter lstCompile weist OpenGL an, die Liste sofort zu kompilieren.
      Call DrawScene 'Zeichnen der Szene
   glEndList 'fertig
End Sub

Listing 2: Erzeugung der Displayliste

Die Prozedur DrawScene zeichnet die mittels LoadWorld eingelesenen Daten für eine Kugel die in unserem Fall aus 4511 Dreiecken besteht.

Public Sub DrawScene()
   'Darstellung der eingelesenen Daten in einer Schleife
   For I = 0 To Sektor(0).Sct_NummTriangle - 1 'alle Dreiecke abarbeiten
       'Auswahl der gewünschten Textur
       If Sektor(0).Triangle(I).T > 0 Then glBindTexture GL_TEXTURE_2D, Texture(Sektor(0).Triangle(I).T)
       glBegin bmTriangles
          For J = 0 To 2 '3 Punkte je Dreieck
              With Sektor(0).Triangle(I).Vertex(J)
                 glTexCoord2f .U, .V: glVertex3f .X, .Y, .Z
              End With
          Next
       glEnd
   Next
End Sub

Listing 3: DrawScene

Dann müssen wir das Ganze nur noch testen. Damit der Unterschied deutlich wird, zeigen wir im Titel der Form die gezeichneten Frames je Sekunde an. Der entsprechende Code sollte verständlich sein. Um zwischen direktem Zeichnen und Displayliste hin- und her zu schalten, legen wir die Darstellung über die Taste D fest.

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
   '...
   If KeyCode = vbKeyD Then
      Disp = Not Disp
   End If
End Sub

Public Sub Main()
   '...
   T1 = Timer 'Zeitpunkt Beginn der Darstellung
   glClear clrColorBufferBit Or clrDepthBufferBit ' löscht das Fenster und den Tiefenpuffer
   glLoadIdentity 'setzt die aktuelle Modell-Matrix zurück
   glTranslatef 0#, 0#, -8#
   glRotatef r4eckY, 0#, 1#, 0# 'Drehen des Würfels um die Y Achse
 
   If Disp Then
      glCallList DisplayLists(0) 'Darstellung über Displayliste
   Else
      Call DrawScene 'direktes Zeichnen
   End If
 
   SwapBuffers (frm.hDC) 'Puffer tauschen (Double Buffering)
   DoEvents
 
   r4eckY = r4eckY + 0.4 'Winkel für Drehung hochzählen
 
   T2 = Timer 'Zeitpunkt Ende der Darstellung
   Ct = Ct + 1 'Zähler für Frames
   Fps = Fps + (T2 - T1) 'Verbrauchte Zeit hochzählen
   If Fps > 1 Then 'nach einer Sekunde ausgeben
      If Disp Then
         frm.Caption = Ct & " Frames/Sec mit Displayliste"
      Else
         frm.Caption = Ct & " Frames/Sec bei direktem Zeichnen"
      End If
      Fps = Fps - 1
      Ct = 0
   End If
   '...
End Sub

Listing 4: KeyDown-Ereignis und Sub Main

Es geht weiter  

So, das war schon alles.
Bei sehr schnellen Rechnern mit einfacher Grafikkarte kann es bei diesem Beispiel vorkommen, dass direktes Zeichnen schneller ist als die Displayliste. Je besser aber die Grafikkarte um so mehr werden die Unterschiede sichtbar. Für ältere Rechner und/oder einfache Grafikkarten ist dem Beispielprojekt eine weitere Kugel mit nur 1983 Dreiecken beigefügt. Mein eigener Testrechner mit einem Dual Core 1 Prozessor und einer einfachen Intel Graphics Media Accelerator Grafikkarte mit 128 MByte Shared Memory bring es bei direktem Zeichnen gerade noch auf 18 Frames/Sekunde. Das zeigt die Grenzen von VB in der 3D-Welt auf. Für rund 4500 Dreiecke werden in der inneren Schleife von DrawScene ca. 13500 Vertices (Punkte) gesetzt. Da Animationen unterhalb von 24 Frames/Sekunde häufig ruckeln, sollte dieser Wert eigentlich nicht unterschritten werden.
Wenn wir das jetzt weiter durchdenken würde das bedeuten, wir könnten nur ca. 10000 Vertices rendern. Dem ist tatsächlich so. Doch OpenGL bietet Möglichkeiten, diese Einschränkung zu relativieren. Das Geheimnis heißt Quadriken und hat in Kapitel 9 (Noch nicht veröffentlicht) sein kurzes, aber eindrucksvolles Debüt.

Beispielprojekt  

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