kind: reference search: Matrix, Matrizen, mat4, mat3, Transformation, drehen, strecken, verschieben, Perspektive, Projektion, homogene Koordinaten, transponieren, Inverse, Kovarianzmatrix, Kamera, view, projection, Float32Array, spaltenweise, Achse, Rodrigues, Quaternion, Quaternionen, Slerp, Eulerwinkel, gimbal lock, kardanische Blockade

Matrizen

Eine Matrix ist eine Tabelle aus Zahlen, die einen Punkt dreht, streckt, verschiebt oder auf den Bildschirm bringt, so wie in 3D-Grafik mit WebGL und in Shadern, und die in Gaussian Splatting die Form eines Splats beschreibt. Hier steht, wie man mit ihr rechnet was die einzelnen Matrizen tun und wie Quaternionen eine Drehung in vier Zahlen speichern. Mit Punkten und Richtungen selbst geht es unter Vektoren.

1. Zahlen in Zeilen und Spalten

Matrix mal Vektor

Eine Matrix sind Zahlen in Zeilen und Spalten. Eine 2 × 2-Matrix hat zwei Zeilen und zwei Spalten:

$$M = \begin{pmatrix} a & b \\ c & d \end{pmatrix}$$

Mal einen Vektor genommen, gibt sie einen neuen Vektor: Jede Zeile wird mit dem Vektor multipliziert wie beim Skalarprodukt, Zahl für Zahl, und die Produkte zusammengezählt.

$$\begin{pmatrix} a & b \\ c & d \end{pmatrix} \begin{pmatrix} x \\ y \end{pmatrix} = \begin{pmatrix} a x + b y \\ c x + d y \end{pmatrix}$$

Zum Beispiel macht \(\begin{pmatrix} 2 & 0 \\ 0 & 1 \end{pmatrix}\) aus \((3, 4)\) den Punkt \((6, 4)\): Alles wird doppelt so breit, die Höhe bleibt.

Die Spalten verraten, was sie tut

Die erste Spalte ist, wohin der Punkt \((1, 0)\) kommt, die zweite, wohin \((0, 1)\) kommt. Weil jeder andere Punkt aus diesen beiden zusammengesetzt ist, weiß man damit, was die Matrix mit allen Punkten tut. Wer eine Matrix bauen will, überlegt sich also, wohin die Achsen sollen, und schreibt sie als Spalten hin.

2. Drehen, strecken, spiegeln

Um den Winkel \(\theta\) gegen den Uhrzeigersinn drehen, strecken und spiegeln:

was Matrix in 2D was mit den Achsen passiert
nichts (Einheitsmatrix) \(\begin{pmatrix} 1 & 0 \\ 0 & 1 \end{pmatrix}\) \((1, 0)\) bleibt
drehen um \(\theta\) \(\begin{pmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{pmatrix}\) \((1, 0)\) wird \((\cos\theta, \sin\theta)\)
strecken um \(s_x\) und \(s_y\) \(\begin{pmatrix} s_x & 0 \\ 0 & s_y \end{pmatrix}\) \((1, 0)\) wird \((s_x, 0)\)
an der y-Achse spiegeln \(\begin{pmatrix} -1 & 0 \\ 0 & 1 \end{pmatrix}\) \((1, 0)\) wird \((-1, 0)\)
scheren \(\begin{pmatrix} 1 & k \\ 0 & 1 \end{pmatrix}\) \((1, 0)\) bleibt, \((0, 1)\) wird \((k, 1)\)

In den Bildern ist das F vorher gestrichelt und nachher blau. Die roten und grünen Pfeile sind, wohin \((1, 0)\) und \((0, 1)\) kommen: die beiden Spalten der Matrix.

Im Raum dreht man um eine Achse, und die Zahl auf dieser Achse bleibt. Um die y-Achse, wie eine Figur, die sich auf der Stelle dreht:

$$R_y(\theta) = \begin{pmatrix} \cos\theta & 0 & \sin\theta \\ 0 & 1 & 0 \\ -\sin\theta & 0 & \cos\theta \end{pmatrix}$$

Um die x-Achse (nicken) stehen Kosinus und Sinus in der zweiten und dritten Zeile und Spalte, um die z-Achse (kippen) in der ersten und zweiten.

3. Hintereinander: Matrix mal Matrix

Zwei Matrizen lassen sich zu einer zusammenfassen: In \(A \cdot B\) ist die Zahl in Zeile \(i\), Spalte \(j\) das Skalarprodukt aus Zeile \(i\) von \(A\) und Spalte \(j\) von \(B\). Die neue Matrix tut dasselbe wie erst \(B\) und dann \(A\):

$$(A \cdot B) \cdot v = A \cdot (B \cdot v)$$

Gelesen wird also von rechts nach links, und die Reihenfolge zählt: Erst drehen und dann verschieben bringt ein Modell an eine andere Stelle als erst verschieben und dann um den Ursprung drehen, das Modell kreist dann um ihn.

Darum steht in einem Grafikprogramm projection * view * model * punkt: zuerst das Modell an seinen Platz, dann in die Sicht der Kamera, zuletzt auf den Bildschirm.

Für viele Punkte rechnet man das Produkt der Matrizen einmal aus und nimmt dann jeden Punkt nur noch mit einer Matrix mal. So macht es die Grafikkarte mit Millionen Ecken.

4. Verschieben mit vier Zahlen

Eine 3 × 3-Matrix kann drehen und strecken, aber nicht verschieben: Der Ursprung bleibt immer, wo er ist. Der Trick ist eine vierte Zahl, \(w\). Ein Punkt bekommt \(w = 1\), eine Richtung \(w = 0\) (homogene Koordinaten). Dann verschiebt diese Matrix um \((t_x, t_y, t_z)\):

$$\begin{pmatrix} 1 & 0 & 0 & t_x \\ 0 & 1 & 0 & t_y \\ 0 & 0 & 1 & t_z \\ 0 & 0 & 0 & 1 \end{pmatrix} \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \begin{pmatrix} x + t_x \\ y + t_y \\ z + t_z \\ 1 \end{pmatrix}$$

Die vierte Spalte kommt nur über das \(w = 1\) des Punktes ins Ergebnis. Eine Richtung mit \(w = 0\) bleibt, wie sie ist: Eine Richtung hat keinen Ort, den man verschieben könnte. Darum sind in Grafikprogrammen fast alle Matrizen 4 × 4 (mat4), und drehen, strecken und verschieben lassen sich zu einer einzigen zusammenfassen.

5. Die wichtigsten Matrizen in 3D

Verschieben, strecken, drehen

Mit vier Zahlen je Punkt sind das die Bausteine, aus denen jede Bewegung eines Modells zusammengesetzt wird:

Matrix tut 4 × 4
\(T(t_x, t_y, t_z)\) verschieben \(\begin{pmatrix} 1 & 0 & 0 & t_x \\ 0 & 1 & 0 & t_y \\ 0 & 0 & 1 & t_z \\ 0 & 0 & 0 & 1 \end{pmatrix}\)
\(S(s_x, s_y, s_z)\) strecken \(\begin{pmatrix} s_x & 0 & 0 & 0 \\ 0 & s_y & 0 & 0 \\ 0 & 0 & s_z & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix}\)
\(R_x(\theta)\) um die x-Achse drehen (nicken) \(\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos\theta & -\sin\theta & 0 \\ 0 & \sin\theta & \cos\theta & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix}\)
\(R_y(\theta)\) um die y-Achse drehen (sich umdrehen) \(\begin{pmatrix} \cos\theta & 0 & \sin\theta & 0 \\ 0 & 1 & 0 & 0 \\ -\sin\theta & 0 & \cos\theta & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix}\)
\(R_z(\theta)\) um die z-Achse drehen (kippen) \(\begin{pmatrix} \cos\theta & -\sin\theta & 0 & 0 \\ \sin\theta & \cos\theta & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix}\)

Dieselben Bewegungen wie oben in der Ebene, jetzt mit dem F als Block im Raum. Grau ist der Block vorher, blau der Block nachher; verdeckte Kanten sind gestrichelt, beim grauen Block gepunktet. Die x-Achse ist rot, die y-Achse grün, die z-Achse blau und zeigt zu dir.

Zusammensetzen

Ein Modell soll doppelt so groß werden, sich um 90° um die z-Achse drehen und dann um 2 nach rechts rücken. Gelesen von rechts nach links ist das

$$M = T(2, 0, 0) \cdot R_z(90°) \cdot S(2, 2, 2) = \begin{pmatrix} 0 & -2 & 0 & 2 \\ 2 & 0 & 0 & 0 \\ 0 & 0 & 2 & 0 \\ 0 & 0 & 0 & 1 \end{pmatrix}$$

Der Punkt \((1, 0, 0)\) wird erst zu \((2, 0, 0)\) gestreckt, dann auf \((0, 2, 0)\) gedreht, dann nach \((2, 2, 0)\) verschoben; \(M\) allein, einmal mit dem Punkt multipliziert, gibt dasselbe. Die übliche Reihenfolge ist erst strecken, dann drehen, dann verschieben, \(T \cdot R \cdot S\): So streckt und dreht sich das Modell um seine eigene Mitte. Erst verschoben und dann gedreht, kreist es um den Ursprung der Welt.

6. Drehen um eine beliebige Achse

Eine Tür dreht sich um ihre Angeln, ein Kreisel um seine schräge Achse: Oft ist die Achse keine der drei Koordinatenachsen. Für eine Achse \(\vec{k}\) mit der Länge 1 und einen Winkel \(\theta\) zerlegt man einen Vektor \(\vec{v}\) in zwei Teile. Der Teil entlang der Achse, \((\vec{k} \cdot \vec{v})\,\vec{k}\), bleibt, wie er ist. Der Rest steht quer zur Achse und dreht sich in der Ebene senkrecht zu ihr um \(\theta\). Zusammen ergibt das die Formel von Rodrigues (mit dem Skalarprodukt und dem Kreuzprodukt, Handbuch, Vektoren):

$$\vec{v}' = \vec{v}\cos\theta + (\vec{k} \times \vec{v})\sin\theta + \vec{k}\,(\vec{k} \cdot \vec{v})\,(1 - \cos\theta)$$

Als Matrix, mit \(c = \cos\theta\), \(s = \sin\theta\), \(t = 1 - c\) und \(\vec{k} = (x, y, z)\):

$$R = \begin{pmatrix} c + x^2 t & xy\,t - z s & xz\,t + y s \\ yx\,t + z s & c + y^2 t & yz\,t - x s \\ zx\,t - y s & zy\,t + x s & c + z^2 t \end{pmatrix}$$

Mit \(\vec{k} = (0, 1, 0)\) wird daraus genau \(R_y(\theta)\) von oben. Im Bild dreht sich das F um 60° um die Diagonale \(\vec{k} = \frac{1}{\sqrt{3}}(1, 1, 1)\), die zwischen den drei Achsen liegt:

Ein F als Block, um 60 Grad um eine schräge Achse gedreht, die orange gestrichelt vom Ursprung nach rechts oben zeigt, auf der Diagonale zwischen x-, y- und z-Achse. Das F liegt danach schräg im Raum, nach links gekippt; dahinter der graue Block vorher.

Dieselbe Drehung ließe sich auch aus Drehungen um x, y und z zusammensetzen; die Formel sagt sie in einem Schritt. Sie heißt nach Olinde Rodrigues, der sie 1840 veröffentlicht hat; Leonhard Euler kannte sie schon 1770.

7. Quaternionen

Vier Zahlen für eine Drehung

Eine Drehmatrix hat neun Zahlen, eine Drehung braucht aber nur drei Angaben: zwei für die Richtung der Achse und eine für den Winkel. Ein Quaternion kommt mit vier Zahlen aus. Für die Drehung um den Winkel \(\theta\) um die Achse \(\vec{k}\) mit der Länge 1 ist

$$q = (w, x, y, z) = \left(\cos\tfrac{\theta}{2},\ \sin\tfrac{\theta}{2}\,\vec{k}\right)$$

Ein Quaternion für eine Drehung hat immer die Länge 1, \(w^2 + x^2 + y^2 + z^2 = 1\). Die Drehung um 90° um die z-Achse ist zum Beispiel \(w = z = \cos 45° \approx 0{,}707\) und \(x = y = 0\). Der halbe Winkel kommt daher, dass man beim Drehen zweimal mit \(q\) multipliziert, einmal von links und einmal von rechts.

Rechnen mit Quaternionen

Schreibt man \(\vec{u} = (x, y, z)\) für den Teil mit der Achse, dann sind zwei Drehungen hintereinander das Produkt der beiden Quaternionen:

$$q_1\, q_2 = \left(w_1 w_2 - \vec{u}_1 \cdot \vec{u}_2,\ \ w_1 \vec{u}_2 + w_2 \vec{u}_1 + \vec{u}_1 \times \vec{u}_2\right)$$

Wie bei Matrizen kommt es auf die Reihenfolge an: \(q_1 q_2\) dreht erst mit \(q_2\), dann mit \(q_1\). Rückwärts dreht \(\bar{q} = (w, -x, -y, -z)\), dieselbe Achse andersherum. Einen Vektor \(\vec{v}\) dreht man, indem man ihn als \(p = (0, \vec{v})\) schreibt und \(q\, p\, \bar{q}\) ausrechnet; heraus kommt \((0, \vec{v}')\). Übrigens drehen \(q\) und \(-q\) genau gleich.

Für die Grafikkarte macht man aus dem Quaternion meist wieder eine Matrix:

$$R = \begin{pmatrix} 1 - 2(y^2 + z^2) & 2(xy - wz) & 2(xz + wy) \\ 2(xy + wz) & 1 - 2(x^2 + z^2) & 2(yz - wx) \\ 2(xz - wy) & 2(yz + wx) & 1 - 2(x^2 + y^2) \end{pmatrix}$$

Mit \(w = z \approx 0{,}707\) und \(x = y = 0\) steht da \(R_z(90°)\): in der ersten Zeile 0, −1, 0.

Warum nicht drei Winkel?

Drei Winkel hintereinander, etwa erst um y, dann um x, dann um z (beim Flugzeug Gieren, Nicken und Rollen, die Eulerwinkel), sind leicht zu verstehen, haben aber zwei Schwächen:

  • Kardanische Blockade (englisch gimbal lock): Steht der mittlere Winkel auf 90°, drehen der erste und der dritte Winkel um dieselbe Achse. Eine Richtung zum Drehen fehlt dann, bis man den mittleren Winkel wieder verstellt. Bei Apollo 11 maßen drei solche Ringe die Lage der Kapsel. Michael Collins, der in ihr um den Mond kreiste, fragte nach der Landung: »How about sending me a fourth gimbal for Christmas?«
  • Mischen: Wer zwischen zwei Lagen eine Bewegung braucht und dafür die drei Winkel mischt, bekommt krumme, ungleichmäßige Drehungen.

Quaternionen haben beides nicht. Zwischen zwei Quaternionen \(q_1\) und \(q_2\) mischt Slerp (spherical linear interpolation) so, dass sich das Modell mit gleichmäßiger Geschwindigkeit um eine feste Achse dreht, auf dem kürzesten Weg; Ken Shoemake hat das 1985 in die Computergrafik gebracht. Ist \(\cos\Omega = q_1 \cdot q_2\) (die vier Zahlen paarweise multipliziert und addiert), dann ist

$$\operatorname{slerp}(q_1, q_2, t) = \frac{\sin((1 - t)\,\Omega)}{\sin\Omega}\, q_1 + \frac{\sin(t\,\Omega)}{\sin\Omega}\, q_2$$

Ist \(q_1 \cdot q_2\) negativ, nimmt man vorher \(-q_2\), sonst geht es den langen Weg herum. Noch ein Vorteil: Eine Matrix, die über viele Bilder immer wieder mit kleinen Drehungen multipliziert wird, sammelt Rundungsfehler und beginnt zu verzerren. Ein Quaternion teilt man einfach durch seine Länge, und es ist wieder eine reine Drehung.

William Rowan Hamilton, Schwarzweißfoto: ein älterer Mann mit hoher Stirn und Glatze, grauen Locken an den Seiten und Koteletten, weißer Halsbinde und dunklem Mantel, mit leicht zusammengekniffenem, nachdenklichem Blick.

William Rowan Hamilton (1805–1865), irischer Mathematiker, Physiker und Astronom. Mit 17 kam er an das Trinity College in Dublin und wurde noch als Student Professor für Astronomie. Komplexe Zahlen kann man als Punkte in der Ebene sehen; Hamilton suchte dasselbe für Punkte im Raum.

Am 16. Oktober 1843 ging er mit seiner Frau am Royal Canal in Dublin spazieren, als ihm die Lösung einfiel: vier Zahlen statt drei, mit den Regeln \(i^2 = j^2 = k^2 = ijk = -1\). Er ritzte sie mit seinem Taschenmesser in die nahe Broom Bridge. Heute drehen Quaternionen Modelle in Spielen, in glTF-Dateien und die Splats in Gaussian Splatting.

Foto: 1885, Library of Congress, gemeinfrei, zugeschnitten (Wikimedia Commons)

Wo man sie trifft

  • glTF, das Dateiformat vieler 3D-Modelle, speichert die Drehung jedes Teils als Quaternion, in der Reihenfolge \((x, y, z, w)\).
  • Gaussian Splatting speichert die Drehung jedes Splats in rot_0 bis rot_3, in der Reihenfolge \((w, x, y, z)\) und nicht unbedingt mit der Länge 1; vor dem Umrechnen teilt man durch die Länge (Gaussian Splatting).
  • Unity speichert die Drehung jedes Objekts als Quaternion, auch wenn man im Editor drei Winkel einstellt; Godot und three.js haben dafür einen eigenen Typ Quaternion.

8. Rückgängig machen

Die Inversen der Bausteine

Die Inverse \(M^{-1}\) macht rückgängig, was \(M\) tut. Für die Bausteine ist sie leicht hinzuschreiben, ohne zu rechnen:

Matrix Inverse denn
\(T(t)\) \(T(-t)\) zurückschieben
\(S(s)\) \(S(1/s)\) wieder schrumpfen; mit \(s = 0\) geht es nicht
\(R(\theta)\) \(R(-\theta) = R^\top\) zurückdrehen; zur Transponierten unten mehr

Die Inverse eines Produkts

Ein Produkt macht man rückgängig, indem man die Schritte rückwärts und in umgekehrter Reihenfolge geht, wie beim Ausziehen erst die Schuhe, dann die Socken:

$$(A \cdot B)^{-1} = B^{-1} \cdot A^{-1}$$

Für \(M = T \cdot R \cdot S\) von oben ist \(M^{-1} = S^{-1} \cdot R^{-1} \cdot T^{-1}\): erst zurückschieben, dann zurückdrehen, dann wieder schrumpfen.

Die Kamera als Inverse

Damit ergibt sich die View-Matrix wie von selbst. Steht die Kamera mit \(C = T(\text{auge}) \cdot R\) in der Welt, an der Stelle \(\text{auge}\) und um \(R\) gedreht, muss die View-Matrix das rückgängig machen, damit die Kamera im Ursprung landet:

$$\text{view} = C^{-1} = R^{-1} \cdot T(\text{auge})^{-1} = R^\top \cdot T(-\text{auge})$$

Erst die Welt so verschieben, dass das Auge im Ursprung liegt, dann sie entgegen der Kamera drehen. So baut auch 3D-Grafik mit WebGL seine View-Matrix, aus Drehungen und einem translate mit negativen Zahlen.

9. Kamera und Perspektive

Die Kamera

Eine Kamera ist dieselbe Rechnung rückwärts: Statt die Kamera in die Welt zu stellen, rückt die View-Matrix die ganze Welt so, dass die Kamera im Ursprung steht und in Richtung −z schaut. Steht die Kamera bei \((0, 0, 5)\), verschiebt die View-Matrix alles um \((0, 0, -5)\); dreht sie sich nach links, dreht die View-Matrix die Welt nach rechts.

Die Perspektive

Die Projektion bringt den Raum vor der Kamera auf den Bildschirm, und was weiter weg ist, wird kleiner. Eine Matrix kann nicht teilen, darum schreibt sie die Entfernung in die vierte Zahl: Nach der Projektion ist \(w = -z\). Die Grafikkarte teilt danach \(x\), \(y\) und \(z\) durch \(w\):

$$x_\text{Bildschirm} = \frac{x}{w}, \qquad y_\text{Bildschirm} = \frac{y}{w}$$

Doppelt so weit weg heißt doppelt so großes \(w\), also halb so groß auf dem Bildschirm. Die Ergebnisse von −1 bis 1 heißen Clip-Koordinaten in WebGL: −1 ist der linke oder untere Rand, 1 der rechte oder obere. Die übliche Perspektivmatrix für den Öffnungswinkel \(\theta\), das Seitenverhältnis \(a\) und die Grenzen \(n\) (nah) und \(f\) (fern), mit \(s = 1 / \tan(\theta / 2)\):

$$P = \begin{pmatrix} s / a & 0 & 0 & 0 \\ 0 & s & 0 & 0 \\ 0 & 0 & \frac{f + n}{n - f} & \frac{2 f n}{n - f} \\ 0 & 0 & -1 & 0 \end{pmatrix}$$

10. Transponieren

Die Transponierte \(M^\top\) vertauscht Zeilen und Spalten: Die erste Zeile wird die erste Spalte. \(M^{-1} \cdot M\) ist die Einheitsmatrix; nicht jede Matrix hat eine Inverse, eine, die alles auf eine Linie drückt, lässt sich nicht umkehren.

Bei einer Drehung ist es einfach: Die Inverse ist die Transponierte, \(R^{-1} = R^\top\), denn zurückdrehen heißt um denselben Winkel in die andere Richtung, und \(\sin(-\theta) = -\sin\theta\) tauscht genau die beiden Zahlen außerhalb der Diagonalen.

Eine Normale dreht man mit dem Modell mit, aber nicht mit derselben Matrix, wenn das Modell ungleich gestreckt ist: Ein in die Breite gezogener Kreis hat an der Seite eine Normale, die steiler wird, nicht flacher. Die richtige Matrix für Normalen ist \((M^{-1})^\top\); für reine Drehungen ist das wieder \(M\) selbst.

11. Die Form eines Ellipsoids

Eine Matrix kann auch eine Form beschreiben. Ein Ellipsoid entsteht aus einer Kugel, die man mit \(S\) entlang der Achsen streckt und mit \(R\) dreht. Seine Kovarianzmatrix ist

$$\Sigma = R \, S \, S^\top R^\top$$

Sie ist symmetrisch, die Zahl in Zeile \(i\), Spalte \(j\) ist dieselbe wie in Zeile \(j\), Spalte \(i\): Von neun Zahlen sind nur sechs verschieden. Auf der Diagonalen steht, wie breit das Ellipsoid entlang x, y und z ist (im Quadrat), daneben, wie schräg es liegt. So speichert jeder Splat in Gaussian Splatting seine Form. Von der Kamera aus gesehen wird daraus eine 2 × 2-Matrix, eine Ellipse auf dem Bildschirm.

12. In JavaScript, GLSL und Python

JavaScript (WebGL) GLSL Python (numpy)
Matrix 16 Zahlen in einem Array, spaltenweise mat4, mat3 np.array([[…], […]]), zeilenweise
Matrix mal Vektor selbst geschrieben m * v m @ v
Matrix mal Matrix selbst geschrieben a * b a @ b
transponieren selbst geschrieben transpose(m) m.T
umkehren selbst geschrieben inverse(m) np.linalg.inv(m)
an den Shader gl.uniformMatrix4fv(ort, false, m) uniform mat4 view;

Spaltenweise heißt: Die ersten vier Zahlen im Array sind die erste Spalte, nicht die erste Zeile. Die Verschiebung \((t_x, t_y, t_z)\) steht deshalb an den Indizes 12, 13 und 14. Wer eine Matrix zeilenweise hinschreibt und so an WebGL gibt, bekommt die Transponierte: Statt zu verschieben, verzerrt sie den Würfel. In numpy ist * die Multiplikation Zahl für Zahl; das Matrixprodukt ist @.

13. Zum Nachschlagen