Table of Contents
Beispiel 1 - Pyglet's graphics.py wird interaktivHier geht es um eine Reihe von Python-Programmen, die ich gemacht habe, um die Library Pyglet, OpenGL und insbesondere GLSL besser zu verstehen. Das ist das erste Beispiel - begonnen habe ich mit graphics.py von Alex Holkner. Das Original befindet sich im Pyglet Repository. Ich habe die Funktion erweitert, um eine Basis für alle GLSL Demoprogramme zu haben.
und ein paar Screenshots: Um die Demo laufen zu lassen, benötigt man Pyglet und das “euclid.py” Modul von Alex Holkner - alles dafür Nötige ist auf der Seite zur Installation. (Falls jemand “euclid.py” sucht: das File liegt im Verzeichnis App/Lib/site-packages/shader des Installationspaketes glslpythonpack.zip). Die erweiterte Version zeigt:
HTML-TextEin nettes Feature der Pyglet Library - mit HTML-Code in einem String, kann man ein Objekt erzeugen mit label = pyglet.text.HTMLLabel(html, # location=location, width=window.width//2, multiline=True, anchor_x='center', anchor_y='center') und dieses im “on_draw()” Event Handler darstellen mit @window.event def on_draw(): label.draw() jedesmal wenn das Fenster neu gezeichnet wird. Ich lasse den Text durch ein Pyglet Event nach 10 Sekunden verschwinden: def dismiss_dialog(dt): global showdialog showdialog = False pyglet.clock.schedule_once(dismiss_dialog, 10.0) Behandlung der TastaturDas ist auch recht einfach - um die “showdialog”-Variable mit der “H”-Taste umzuschalten schreibe ich @window.event def on_key_press(symbol, modifiers): global showdialog if symbol == key.H: showdialog = not showdialog Das ist eine nette Eigenschaft von Python - leicht zu lesen und zu verbessern FPS Zähler anzeigenDas ist eine Pyglet Standardfunktion. Das Einzige, was dabei zu beachten ist, dass in die aktuelle Texture gerendert wird, also muss die Textur aktiv sein, um den Zähler zu sehen. fps_display = pyglet.clock.ClockDisplay() # see programming guide pg 48 @window.event def on_draw(): fps_display.draw() Kugel mit gleichmässig verteilten EckenZusätzlich zum “batch1”, der die Vertex Arrays für den Torus enthält: batch1 = pyglet.graphics.Batch() torus = Torus(1, 0.3, 80, 25, batch=batch1) wollte ich einen “batch2” (Umschaltung zwischen den beiden Figuren mit der “F”-Taste) mit einer regelmässigen Kugel: batch2 = pyglet.graphics.Batch() sphere = Sphere(1.2, 4, batch=batch2) Warum regelmässig ? Wenn Du Dir eine Weltkugel vorstellst mit dem Äquator und den Meridianen, fällt auf, dass an den Polen seltsame Dinge mit den Koordinaten geschehen. Um die zu vermeiden, funktioniert als einfachste Lösung die Dreiecks-Teilung: Finde eine regelmässige (“platonische”) Figur, die sich in eine Kugel einschreiben lässt und ausschliesslich aus gleichseitigen Dreiecken besteht - drei gibt's zur Auswahl:
Ich habe mit einem Oktaeder begonnen, weil dann die Eck-Koordinaten am einfachsten sind: self.vv.append( Vector3( 1.0, 0.0, 0.0 ) ) # North self.vv.append( Vector3(-1.0, 0.0, 0.0 ) ) # South self.vv.append( Vector3( 0.0, 1.0, 0.0 ) ) # A self.vv.append( Vector3( 0.0, 0.0, 1.0 ) ) # B self.vv.append( Vector3( 0.0,-1.0, 0.0 ) ) # C self.vv.append( Vector3( 0.0, 0.0,-1.0 ) ) # D Dann wird jedes Dreieck (rekursiv) in 4 kleinere gleichseitige Dreiecke geteilt. Die neuen Ecken (drei Stück) werden “nach aussen” zur Kugeloberfläche verschoben. Wiederholen bis Du genug hast Hier ein Bild der verschiedenen Rekursions-Schritte. Die Ecken eines Dreiecks sind mit roten Punkten markiert, damit man den Unterteilungs-Algorithmus leicht sieht. Die Implementierung dieses Algorithmus in Python wäre einfach und elegant, aber in seiner einfachen Form entstehen gemeinsame Ecken - diese liegen dann als Duplikate in der Ecken-Liste. Um sie zu vermeiden, muss ich über die “bereits behandelten” Kanten Buch führen: Wenn eine Kante neu ist (“N”), werden die Ecken in die “vertex”-Liste aufgenommen. War die Kante schon dran (“X”), suche ich in der Liste nach der Ecke mit den entsprechenden Koordinaten und verwende deren Index. def myindex( self, list, value ): for idx, obj in enumerate(list): if abs(obj-value) < 0.0001: return idx raise ValueError # not found Die Buchführung macht den Code eher hässlich - Ich habe das dumpfe Gefühl, dass das besser geht (indem ich die Dreiecke irgendwie sinnvoll durchnummeriere - dann könnte ich den gesuchten Index direkt berechnen statt in einer Liste von Fliesskomma-Vektoren herumzusuchen). Na gut, aber hier stehen wir. Für Details schau' in den Pyglet Demo Base Code. Das ganze Ding ist die Basis für meine GLSL Experimente - Wir beginnen mit einer ordentlichen GLSL Beleuchtung (inklusive einem hübschen Glanzlicht). |