Geodreieck und Matrizen, eine Analogie
Mit diesem Tutorial möchte ich vor allem Anfängern unter die Arme greifen, die ihre allerersten Schritte in OpenGL machen. Ich glaube, jeder Anfänger tut sich schwer mit den Befehlen glTranslate, glRotate und glScale. Selbst bei den schon etwas Fortgeschrittenen scheint es noch das eine oder andere Missverständnis zu geben. Sicher, man lernt recht schnell, mit den Dingen richtig umzugehen, dafür gibt es ja erprobte Regeln. Doch ob man die Zusammenhänge auch richtig durchschaut, ist eine andere Sache.
Woran liegt es, dass wir am Anfang solche Probleme mit diesen Befehlen haben? Ich denke, das liegt einmal an den Missverständnissen, die immer wieder kursieren und auf Halbwahrheiten beruhen. Es liegt aber auch daran, dass wir uns die Situation nicht ganz leicht vorstellen können. Auf die Missverständnisse werde ich im Folgetutorial eingehen, und was die Vorstellung betrifft, so soll dieses Tutorial einen Beitrag leisten.
Als ich meine ersten Gehversuche mit OpenGL unternahm, war ich beeindruckt von dem, was Matrizen in OpenGL leisten. Was eine solche Matrix genau ist und vor allem was exakt ihre Funktion ist, davon hatte ich nur eine verschwommene Vorstellung. "Verschiebungen und Rotationen werden in Matrizen gespeichert", las ich irgendwo. Schön, dachte ich, da wird also ein Punkt verschoben, in einer Matrix gespeichert, und am Schluss formt OpenGL aus allen Matrizen ein Bild.
Erst als ich merkte, dass diese Vorstellung überhaupt nicht zu den Ergebnissen auf dem Bildschirm passen wollte, stellte ich mein Verständnis von Matrizen auf den Prüfstand und kam nach und nach zu der Erkenntnis, dass wohl etwas ganz anderes dahinter stecken müsste. Endgültig klar wurde die Sache, als ich erfuhr, dass für das Zeichnen von Szenerien genau eine Matrix zuständig ist, nämlich die Modelview-Matrix. Ein einziges Array von genau 16 Zahlen. Da machte es endgültig klick: die Matrix kann lediglich ein Werkzeug sein, um die Szenerie zu zeichnen, eine Art Schablone.
Werkzeug zum Zeichnen? Das benutzen wir doch auch, wenn wir etwas aufs Papier bringen wollen. Ein Lineal zum Beispiel, oder ein Geodreick. Und in der Tat, beim Vergleich eines Lineals oder Geodreiecks mit einer OpenGL-Matrix stellen sich verblüffende Gemeinsamkeiten heraus. Allerdings gilt das nur bis zu einem gewsissen Grad, alles lässt sich damit nicht veranschaulichen. Aber es reicht, um die Befehle glTranslate und glRotate mit ihren Tücken zu verstehen. Beginnen wir also mit dem Zeichnen ...
Verschiebungen - glTranslate


Das Zeichnen des Quadrates entspricht den 4 Vertexangaben zwischen glBegin (GL_QUADS) und glEnd.

In OpenGL können wir ähnlich verfahren, indem wir die Vertices nach wie vor auf den Welt-Nullpunkt beziehen. Die Eckpunkte des Quadrates (Vertices) haben die Koordinaten (6, 0), (8, 0) (8, 2) und (8, 6).

Dem Verschieben des Geodreicks entspricht in OpenGL der Befehl glTranslate. glTranslate erzeugt eine Verschiebungsmatrix.
An dieser Stelle sollten wir kurz anhalten und uns einige Dinge klarmachen. Das Geodreieck verkörpert ja so etwas wie ein eigenes Koordinatensystem, mit dem Nullpunkt an der bekannten Stelle in der Mitte der Hypotenuse. Wenn wir das Geodreieck verschieben, nehmen wir das (lokale) Koordinatensystem mit und plazieren es an irgendeiner Stelle im globalen Weltkoordinatensystem. Alle nun folgenden Zeichenbefehle beziehen sich auf das lokale Koordinatensystem und sind damit von der vorangegangenen Verschiebung betroffen.


Wenn wir das Geodreieck mehrmals nacheinander verschieben, müssen wir nicht jedesmal erst zum Weltmittelpunkt zurück, sondern wir können das Dreieck zuerst irgendwo hinschieben, dort zeichnen, dann weiter verschieben, erneut zeichnen usw.
In OpenGL ist es ähnlich. Jede Matrix baut auf der vorangegangenen auf; alle Verschiebungen beziehen sich auf die zuletzt verwendete Matrix - solange, bis glLoadItentity durchgeführt wird, dann geht's zurück zur Mitte
Rotationen - glRotate
Als nächstes wollen wir das schon vertraute Quadrat rotieren, also untersuchen, wie das mit glRotate ist. Dazu gehen wir wieder in die Mitte zurück (glLoadIdentity).





Doch hoppla, da sollte das Quadrat doch gar nicht hin. Der blaue Pfeil zeigt die verfehlte Position.
Wenn in OpenGL ein Objekt nur um seine eigene Achse und nicht um einen entfernt liegenden Punkt gedreht werden soll, gilt die Regel, dass zuerst glTranslate und dann glRotate durchgeführt wird.
Skalierungen - glScale
Wie glTranslate und glRotate ist auch glScale ein zwar nützlicher, aber nicht unbedingt erforderlicher Befehl. Wir können ein Objekt ohne glScale in beliebiger Größe zeichnen, indem wir die Vertices entsprechend anpassen. Um das Quadrat mit halber Größe zu zeichnen, würden wir nicht mehr mit den Koordinaten 0 und 2, sondern mit den Koordinaten 0 und 1 oder auch -0.5 und +0.5 arbeiten. Oder wir verwenden in der Vertexliste Variablen und können dieselbe Zeichenfunktion für beliebige Objektgrößen benutzen. glScale kann die Sache aber vereinfachen. Im folgenden geht es immer um den Skalierungsfaktor 0.5; das Quadrat soll in halber Größe gezeichnet werden.
Um diese Halbierung mit dem Geodreieck nachzuvollziehen, nehmen wir einfach ein kleineres Dreieck, dass außerdem eine engere Skala hat.





Hoppla, das Quadrat sollte doch weiter verschoben werden! Wenn in OpenGL nur der Gegenstand skaliert werden soll, nicht aber der Verschiebemaßstab, muss zuerst verschoben und dann skaliert werden.
Damit dürfte nun klar sein, warum wir zum Zeichnen von Objekten in OpenGL zuerst glTranslate bemühen und anschließend glRotate bzw. glScale. Doch wie verhält es sich mit der Reihenfolge von glRotate und glScale? Gibt es hierbei auch Regeln, die einzuhalten sind? Sofern wir in allen drei Dimensionen die gleiche Skalierung benutzen, kann das Geodreieck die Frage beantworten. Aber ...
Die Grenzen des Geodreiecks
Wenn wir glScale mit unterschiedlichen Skalierungsfaktoren aufrufen, dann kann uns das Geodreick keine Anschauungshilfe mehr geben. Es ist dafür nicht mehr geeignet, denn es müsste mit zwei verschiedenen Skalen ausgestattet sein. Überhaupt ist die unterschiedliche Skalierung eine Angelegenheit, die manche Tücke in sich birgt. Es beginnt schon beim Koordinatensystem; das Gitternetz besteht nicht mehr aus Quadraten, sondern aus Rechtecken. Das hat u.a. zur Folge, dass sich die Winkel verschieben.
Highlight ist die unterschiedliche Skalierung in Verbindung mit einer Rotation. Nur als Gedankenexperiment: Was geschieht, wenn wir zuerst skalieren, dann rotieren? Der Punkt wird nicht mehr auf einer Kreisbahn um den Koordinatennullpunkt gedreht, sondern auf einer elliptischen Bahn. Im dreidimensionalen Raum tritt ein Ellipsoid an die Stelle der Kugel. Das sind Rotationen, mit der wir uns nur schlecht anfreunden können, denn beim Drehen wird die Form verändert. Umgekehrt sieht's etwas freundlicher aus. Wenn wir zuerst drehen und dann skalieren, gibt's nur die Spreizung.
Das soll erst mal reichen. Ich denke, wenn wir ein Gespür dafür bekommen haben, wie bei jeder Aktion ein neues Koordinatensystem entsteht, dass in das vorherige eingebettet ist, dürfte es nicht mehr allzu schwer fallen, die Transformationsbefehle glTranslate, glRotate und glScale durchdacht anzuwenden. Im zweiten Teil des Tutorials geht es im Prinzip um die gleiche Thematik, aber mit anderen Schwerpunkten. Dann rückt die Matrix in den Vordergrund.