Computergrafik: Unsere OpenGL-Achterbahn

Der Kurs Computergrafik (CG) ging nur das halbe Semester über, dafür mit zwei Terminen pro Woche. Endabgabe fürs Praktikum war es, mit Python und OpenGL eine Achterbahn zu bauen. Genau sahen die abzuhakenden Punkte wie folgt aus:

  • Die Bahn der Achterbahn soll als geschlossene B-Spline-Kurve beschrieben werden. (Dazu kommt gleich noch etwas.)
  • Der Coaster der Achterbahn soll texturiert sein.
  • Die Szene soll von einer Skybox umgeben sein.
  • Mit den Tasten + und - soll die Geschwindigkeit verändert werden können.
  • Mit der Taste K soll zwischen einer Kameraposition auf dem Coaster und einer Gesamtansicht gewechselt werden können.
  • Die Orientierung der Kamera soll per Maus verändert werden können.

Sagen wir es mal so: Wir (meine 3er-Gruppe) haben fast alles irgendwie hinbekommen. Und ja, das Video zu Beginn zeigt eben jenes unseres Endprodukt. (Unter beabsichtigter Nicht-Darstellung einiger Bugs. ;) ). Aufgenommen hat es Kai.

CG war leider alles andere als: „Oh cool, wir klicken uns 3D-Objekte zusammen und machen einfach nur hübsch und das läuft schon.“ Mathe. Ganz viel Mathe. Zu viel Mathe. Sehr viele Matrizen. Eigentlich nur Matrizen. Aber ich bin stolz wie Oskar, dass ich die B-Spline-Funktion lösen konnte. Hier könnt ihr getrost aufhören zu lesen, ich musste einfach meine Lösung noch posten.


Für die geschlossenen B-Spline-Kurven mussten wir den de Boor-Algorithmus implementieren. Nach vielen Versuchen, Zetern und Verzagen habe ich es schließlich iterativ zum Laufen gebracht. Der Code ist für eine Berechnung mit der Ordnung k = 4 gedacht.

def deBoor( bkp, T, k, dt ):
    """
        Wandelt eine gegebene Punkteliste komplett um.
        Liefert die neue Liste.
        bkp: Die KOMPLETTE Liste an Punkten.
        k: Ordnung
        dt: Schrittweite
    """
    t = 3.0
    points = []
    while t < len(bkp)-1:
        start = int(t)-3
        tmp = copy.deepcopy( bkp )
        first = True

        for j in range( 1, k ):
            new_points = []
            if first:
                ix = start
                first = False
            else:
                ix = 0
            for i in range( start+j, start+k ):
                alpha = ( t - T[i] ) / ( T[i-j+k] - T[i] )
                point = [(1-alpha)*tmp[ix][0] + alpha*tmp[ix+1][0],
                         (1-alpha)*tmp[ix][1] + alpha*tmp[ix+1][1],
                         (1-alpha)*tmp[ix][2] + alpha*tmp[ix+1][2]]
                new_points.append( point )
                ix += 1
            tmp = copy.deepcopy( new_points )

        points.append( point )
        t += dt
    return points