Homogene Koordinaten
Die Bearbeitung der Vertexdaten in der OpenGL-Pipeline besteht zum großen Teil in der Umwandlung in ein jeweils anderes Koordinatensystem. In dieser Kette verschiedener Koordinatensysteme tauchen u.a. die sogenannten "homogeneous coordinates" auf. Aber worum handelt es sich bei diesen "homogenen Koordinaten"? Wenn wir vom Wort ausgehen, dann sind das gleichmäßige, einheitlich aufgebaute Vektoren. Das sagt noch nicht viel. Wenn wir unter Wikipedia oder sonstwo im Internet nachschauen, bekommen wir in der Regel einige mathematische Definitionen um die Ohren gehauen, mit denen wir wenig anfangen können - oder auch wollen. Vor allem erklären diese theoretische Erläuterungen nicht, welchen Sinn die homogenen Koordinaten im Kontext von OpenGL haben.
In der Praxis wird man mit homogenen Koordinaten konfrontiert, wenn man einen Drei-Komponenten-Vektor (x, y, z), der ja für die Beschreibung der Position eines Vertex im dreidimensionalen Raum ausreicht, um eine weitere Komponente W auf einen Vier-Komponenten-Vektor (x, y, z, w) erweitern muss, damit er zu den 4x4-Matrizen passt. Nur mit Vier-Komponenten-Vektoren lassen sich Matrizen multiplizieren. Diese zusätzliche Komponente wird so gut wie immer auf 1 gesetzt, was die Frage aufwirft, ob W überhaupt eine Bedeutung hat oder ob es nur eine formale Ergänzung ist.
Doch W hat eine Bedeutung, und um die einigermaßen anschaulich zu erklären, greife ich auf eine 2D-Analogie zurück, die Tom Dalling (www.tomdalling.com) in seinem Blog vorgestellt hat. Dazu projizieren wir ein Bild auf eine Leinwand, und zwar so, dass der Projektor oder Beamer einen Abstand von 1 m von der Leinwand hat. Den Mittelpunkt des Leinwandbildes markieren wir, das ist der Koordinaten-Nullpunkt. Nun suchen wir einen beliebigen Punkt im Bild und bestimmen seine Koordinaten, indem wir den Abstand von der y- und x-Achse messen, z.B. 15 cm rechts von der y-Achse und 22 cm über der x-Achse. Der Vektor, der diese Position beschreibt, lautet also (15, 22).
Dasselbe können wir mit jedem beliebigen Punkt im Bild machen, und solange wir den Abstand von 1 m nicht ändern, haben wir sogar eindeutige, reproduzierbare Ergebnisse. Was aber ist, wenn wir den Abstand vergrößern, z.B auf 3 m? Dann wird natürlich auch das Bild größer, und zwar proportional zum Abstand. Nachdem wir die Mitte wieder genau ausgerichtet haben, finden wir nun den Bildpunkt an der Position (45, 66). Der Vektor wurde also mit dem Faktor 3 multipliziert. Genau dieser Faktor, der im Grunde ein Skalierungsfaktor ist, bildet bei homogenen Koordinaten die zusätzliche Komponente W, auch im dreidimensionalen Raum, wo allerdings das Projektionsmodell versagt.
Nun stellt sich natürlich die Frage, welche Bedeutung der Faktor 1 hat. Nun, die 1 besagt, dass wir es mit "gültigen", vergleichbaren Vektorangaben zu tun haben. Im obigen Anschauungsbeispiel brauchen wir nur den bei 3 m Abstand gemessenen Vektor (45, 66, 3) durch 3 zu dividieren, und wir erhalten den Vektor (15, 22, 1), den wir damit auf den "Normalabstand" 1 m zurückgerechnet haben [1]. Wir können den Vorgang sehr schön mit dem Gleichnamigmachen von Brüchen vergleichen, wobei die Komponente W den Nenner darstellt. Und - wie gesagt - dasselbe gilt natürlich auch für Vier-Komponenten-Vektoren.
Aber das sind zunächst mal Zahlenspiele, denn in aller Regel steht die W-Komponente auf 1. Und die 1 bleibt auch erhalten, wenn wir die üblichen Matrixmultiplikationen zum Verschieben, Rotieren oder Skalieren anwenden. Eine Änderung der W-Komponente ergibt sich meines Wissens nur bei der Multiplikation mit einer Projektionsmatrix, und auch nur dann, wenn es sich um eine perspektivische Projektion handelt. Dabei kommt die Tatsache zum Tragen, dass Objekte umso kleiner dargestellt werden müssen, je weiter sie vom Betrachter (der Kamera) entfernt sind. Doppelte Entfernung - halb so groß. Folglich sorgt die Projektionsmatrix dafür, dass die Entfernung in der W-Komponente festgehalten wird. Anschließend geht OpenGL hin und dividiert die x-, y- und z-Komponenten durch W, und schon haben wir die gewünschte perspektivische Verkleinerung. Als Benutzer haben wir damit nichts zu tun, die Umrechnung auf W = 1 (normalisierte homogene Koordinaten) erledigt OpenGL automatisch.
Also haben wir mit der W-Komponente nicht viel zu tun. Wir ergänzen den dreidimensionalen Vektor einfach um eine 1 - fertig. Natürlich können wir auch andere Werte wählen, etwa um verschiedene Objekte auf einen einheitlichen Maßstab zu skalieren. Aber das erledigt man besser im 3D-Modellierungsprogramm (z.B. Blender), das ist eindeutiger. Im übrigen darf für W auf keinen Fall 0 eingetragen werden, denn durch W wird ja dividiert. Bei einer Division durch 0 verschluckt sich jedes Programm.
Dennoch gibt es auch Fälle, wo W = 0 sein kann, und zwar dann, wenn es sich nicht um Positionen im 3D-Raum handelt, sondern um reine Richtungsangaben. Das können z.B. die Lichtstrahlen einer Lichtquelle sein. Bei Lichtquellen, die das (praktisch) unendlich entfernte Sonnenlicht simulieren sollen, laufen alle Strahlen parallel und der Abstand zur Lichtqelle spielt (praktisch) keine Rolle. Hier wird zur Kennzeichnung W = 0 eingetragen. Aber eben nur zur Kennzeichnung, nicht zum Berechnen.
Bei Lichtquellen, die an bestimmten Stellen in der Szenerie positioniert werden, kommt die Abschwächung der Helligkeit mit wachsendem Abstand zum Tragen, und die W-Komponente erhält eine quantitative Bedeutung. Aber das ist ein anderes Thema.
[1] Natürlich muss es sich nicht um 1 m handeln; der "Normalabstand" kann beliebig sein. Dann würde W eben das W-fache dieses beliebigen Normalabstandes bezeichnen.