Steuerungstasten

nächste Folie (auch Enter oder Spacebar).
vorherige Folie
 d  schaltet das Zeichnen auf Folien ein/aus
 p  wechselt zwischen Druck- und Präsentationsansicht
CTRL  +  vergrößert die Folien
CTRL  -  verkleinert die Folien
CTRL  0  setzt die Größenänderung zurück

Das Weiterschalten der Folien kann ebenfalls durch das Klicken auf den rechten bzw. linken Folienrand erfolgen.

Notation

Typ Schriftart Beispiele
Variablen (Skalare) kursiv $a, b, x, y$
Funktionen aufrecht $\mathrm{f}, \mathrm{g}(x), \mathrm{max}(x)$
Vektoren fett, Elemente zeilenweise $\mathbf{a}, \mathbf{b}= \begin{pmatrix}x\\y\end{pmatrix} = (x, y)^\top,$ $\mathbf{B}=(x, y, z)^\top$
Matrizen Schreibmaschine $\mathtt{A}, \mathtt{B}= \begin{bmatrix}a & b\\c & d\end{bmatrix}$
Mengen kalligrafisch $\mathcal{A}, B=\{a, b\}, b \in \mathcal{B}$
Zahlenbereiche, Koordinatenräume doppelt gestrichen $\mathbb{N}, \mathbb{Z}, \mathbb{R}^2, \mathbb{R}^3$

Grundlagen

Skalarprodukt

scalarproduct
$\mathbf{a}$
$\mathbf{b}$
$\alpha$
$\mathbf{a}_{\mathbf{b}}$
  • Das Skalarprodukt verknüpft zwei Vektoren $\mathbf{a}$ und $\mathbf{b} \in \mathbb{R}^N$. Ergebnis ist ein Skalar.
  • Skalarprodukt: $\langle \mathbf{a}, \mathbf{b}\rangle = \mathbf{a}^\top \mathbf{b} = \sum\limits_{i=1}^N a_i b_i$
  • Skalarprodukt im $\mathbb{R}^3$: $\mathbf{a}^\top \mathbf{b} = (a_1, a_2, a_3) \begin{pmatrix}b_1\\b_2 \\ b_3 \end{pmatrix} = a_1 b_1 + a_2 b_2 + a_3 b_3$
  • Kommutativ: $\langle \mathbf{a}, \mathbf{b}\rangle = \langle \mathbf{b}, \mathbf{a}\rangle$
  • Kosinusgesetz: $\langle \mathbf{a}, \mathbf{b}\rangle = |\mathbf{a}| |\mathbf{b}| \cos \alpha$
  • Orthogonale Vektoren: $\mathbf{a} \perp \mathbf{b} \rightarrow \langle \mathbf{a}, \mathbf{b}\rangle = 0$
  • Senkrechte Projektion: $\mathbf{a}_{\mathbf{b}} = (\mathbf{a}^\top \frac{\mathbf{b}}{|\mathbf{b}| }) \frac{\mathbf{b}}{|\mathbf{b}| }$
  • Verbindung zur Matrixmultiplikation:
    $\begin{bmatrix}a_{11} & a_{12}\\a_{21} & a_{22}\end{bmatrix}\begin{bmatrix}b_{11} & b_{12}\\b_{21} & b_{22}\end{bmatrix} = \begin{bmatrix}\mathbf{a}_1^\top\\ \mathbf{a}_2^\top\end{bmatrix}\begin{bmatrix}\mathbf{b}_1 & \mathbf{b}_2\end{bmatrix} = \begin{bmatrix}\mathbf{a}_1^\top\mathbf{b}_1 & \mathbf{a}_1^\top\mathbf{b}_2\\ \mathbf{a}_2^\top\mathbf{b}_1 & \mathbf{a}_2^\top\mathbf{b}_2 \end{bmatrix}$

Kreuzprodukt

scalarproduct
$\mathbf{a}$
$\mathbf{b}$
$\alpha$
$\mathbf{a} \times \mathbf{b}$
$|\mathbf{a} \times \mathbf{b}|$
  • Das Kreuzprodukt verknüpft zwei Vektoren $\mathbf{a}$ und $\mathbf{b} \in \mathbb{R}^3$. Ergebnis ist ein neuer Vektor $\mathbf{c} = \mathbf{a} \times \mathbf{b} \in \mathbb{R}^3$.
  • Kreuzprodukt: $\begin{pmatrix}a_1\\a_2 \\ a_3 \end{pmatrix} \times \begin{pmatrix}b_1\\b_2 \\ b_3 \end{pmatrix} = \begin{pmatrix}a_2 b_3 - a_3 b_2\\ a_3 b_1 - a_1 b_3 \\ a_1 b_2 - a_2 b_1 \end{pmatrix}$
  • Matrixschreibweise: $\mathbf{a} \times \mathbf{b} = \begin{bmatrix}0 & -a_3 & a_2 \\a_3 & 0 & -a_1 \\ -a_2 & a_1 & 0 \end{bmatrix} \mathbf{b} = [\mathbf{a}]_\times \,\mathbf{b}$
  • Antisymmetrie: $\mathbf{a} \times \mathbf{b} = -\mathbf{b} \times \mathbf{a}$
  • Sinusgesetz: $|\mathbf{a} \times \mathbf{b}| = |\mathbf{a}| |\mathbf{b}| \sin \alpha$
  • Orthogonale Vektoren: $\mathbf{a} \perp (\mathbf{a} \times \mathbf{b}) \perp \mathbf{b}$

3D Transformationen

3D Objekttransformationen

  • Um 3D Objekttransformationen zu realisieren, können wir die gleichen Hilfsmittel anwenden wie im 2D Fall, nämlich lineare Abbildungen und homogene Koordinaten
  • Im Prinzip müssen die Koordinaten "nur" um eine z-Koordinate erweitert werden
  • Transformationen im 3D-Raum sind jedoch im Detail schon komplizierter als im 2D, da sie mehr Parameter haben
  • Besonders die Beschreibung einer Rotation wird schwieriger, da nun drei statt nur einer Achse existieren, um die rotiert werden kann

Rechts- und linkshändiges Koordinatensystem

coordinates
x
y
z
x
y
z
Linkshändiges Koordinatensystem
Rechtshändiges Koordinatensystem
  • Linkshändige Koordinatensysteme werden relativ selten eingesetzt. In dieser Vorlesung werden ausschließlich rechtshändige Koordinatensysteme verwendet.
  • OpenGL verwendet ebenfalls ein rechtshändiges Koordinatensystem: $x$ zeigt nach rechts, $y$ nach oben, und $z$ aus dem Bildschirm heraus

3D Translation

  • Eine Veränderung der Position eines Objekts kann durch eine Translation erreicht werden
  • Eine 2D Translation in Matrixschreibweise
    $\underline{\tilde{\mathbf{p}}} = \begin{pmatrix} \tilde{x} \\ \tilde{y} \\ 1 \end{pmatrix} = \begin{bmatrix}1 & 0& t_x\\ 0 & 1 & t_y \\ 0 & 0 &1\end{bmatrix} \begin{pmatrix} x \\ y \\ 1 \end{pmatrix} $
    kann leicht um die $z$-Koordinate erweitert werden, um eine Translation in alle 3D Raumrichtungen $t_x, t_y, t_z$ zu ermöglichen:
    $\underline{\tilde{\mathbf{P}}} = \begin{pmatrix} \tilde{x} \\ \tilde{y} \\ \tilde{z} \\ 1 \end{pmatrix} = \begin{bmatrix}1 & 0& 0 & t_x\\ 0 & 1 & 0 & t_y \\ 0 & 0 & 1 & t_z \\ 0 & 0 & 0 &1\end{bmatrix} \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \mathtt{T}_t \, \underline{\mathbf{P}}$
  • Die homogenen Punkte $\underline{\mathbf{P}}=(p_1, p_2, p_3, p_4)^\top \in \mathbb{H}^3$ haben nun 4 Koordinaten und $\mathtt{T}$ ist eine $4 \times 4$-Matrix
  • Die kartesischen Koordinaten eines Punkts $\mathbf{P}$ können wie bisher durch Division mit der letzen Koordinate berechnet werden $\mathbf{P}=(\frac{p_1}{p_4}, \frac{p_2}{p_4}, \frac{p_3}{p_4}) \in \mathbb{R}^3$

3D Skalierung

  • Eine Veränderung der Größe eines Objekts kann durch eine Skalierung erreicht werden
  • Eine ungleichförmige Skalierung in alle drei Raumrichtungen $s_x, s_y, s_z$ wird erreicht durch:
    $\underline{\tilde{\mathbf{P}}} = \begin{pmatrix} \tilde{x} \\ \tilde{y} \\ \tilde{z} \\ 1 \end{pmatrix} = \begin{bmatrix}s_x & 0& 0 & 0\\ 0 & s_y & 0 & 0 \\ 0 & 0 & s_z & 0 \\ 0 & 0 & 0 &1\end{bmatrix} \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \mathtt{T}_s \, \underline{\mathbf{P}}$

3D Rotation

  • Im 2D Fall wurde stets um den Koordinatenursprung gedreht. Im 3D Raum gibt es die $x$-, $y$- und $z$-Achse, um die gedreht werden kann
  • Dabei entspricht die Rotation um die $z$-Achse exakt einer 2D Rotation, da nur die $x$- und $y$-Koordinaten eines Punktes verändert werden
  • Rotation um die $z$-Achse um den Winkel $\alpha$:
    $\underline{\tilde{\mathbf{P}}} = \begin{bmatrix}\cos \alpha & -\sin \alpha& 0 & 0\\ \sin \alpha & \cos \alpha & 0 & 0\\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 &1\end{bmatrix} \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \mathtt{T}_{r_z} \, \underline{\mathbf{P}}$

3D Rotation

  • Rotation um die $x$-Achse um den Winkel $\alpha$:
    $\underline{\tilde{\mathbf{P}}} = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0& \cos \alpha & -\sin \alpha& 0 \\ 0 & \sin \alpha & \cos \alpha & 0 \\ 0 & 0 & 0 &1 \\ \end{bmatrix} \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \mathtt{T}_{r_x} \, \underline{\mathbf{P}}$
  • Rotation um die $y$-Achse um den Winkel $\alpha$:
    $\underline{\tilde{\mathbf{P}}} = \begin{bmatrix} \cos \alpha & 0& \sin \alpha& 0 \\ 0 & 1 & 0 & 0 \\ -\sin \alpha & 0 &\cos \alpha & 0 \\ 0 & 0 & 0 &1 \\ \end{bmatrix} \begin{pmatrix} x \\ y \\ z \\ 1 \end{pmatrix} = \mathtt{T}_{r_y} \, \underline{\mathbf{P}}$

Transformationsmatrizen in OpenGL

  • Die $4 \times 4$ Transformationsmatrizen für homogene Punkte werden in OpenGL als ein Float-Array repräsentiert
    GLfloat T[16];
  • Dabei werden die Matrixelemente spaltenweise abgelegt:
    $\mathtt{T} = \begin{bmatrix} t_0 & t_4 & t_8 & t_{12} \\ t_1 & t_5 & t_9 & t_{13} \\ t_2 & t_6 & t_{10} & t_{14} \\ t_3 & t_7 & t_{11} & t_{15} \end{bmatrix}$
    Achtung: zeilenweise ist eigentlich üblicher!

Transformationsmatrizen in OpenGL

  • Für die Transformation von Objekten ist die GL_MODELVIEW Matrix verantwortlich.
  • Die Manipulation dieser Matrix wird aktiviert durch
    glMatrixMode(GL_MODELVIEW);
  • Alle Funktionen zur Matrixmanipulation, wie glLoadIdentity, glLoadMatrix, glMultMatrix glRotate, glScale, glTranslate, glPushMatrix, glPopMatrix werden dann auf der GL_MODELVIEW Matrix ausgeführt.
  • Der aktuelle Zustand der GL_MODELVIEW Matrix beeinflusst die Transformation der Objekte nur dann, wenn diese gezeichnet werden (OpenGL als Zustandsmaschine)

Transformationsmatrizen in OpenGL

  • Die Funktion glLoadIdentity setzt die aktuelle GL_MODELVIEW Matrix gleich einer $4 \times 4$ Einheitmatrix:
    $\mathtt{T}_{\mathrm{\small modelview}}= \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 &0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} = \mathtt{I}_{4 \times 4}$
  • Funktionen zur Transformation, wie glMultMatrix, glRotate, glScale, glTranslate, erzeugen intern eine $4 \times 4$ Matrix, die von rechts auf die aktuelle GL_MODELVIEW Matrix multipliziert wird

    Beispiel:

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(...);
    glRotatef(...);
    glScalef(..);    
    


    $\mathtt{T}_{\mathrm{\small modelview}}= \mathtt{I}$
    $\mathtt{T}_{\mathrm{\small modelview}}= \mathtt{I}\,\mathtt{T}_t$
    $\mathtt{T}_{\mathrm{\small modelview}}= \mathtt{I}\,\mathtt{T}_t\,\mathtt{T}_r$
    $\mathtt{T}_{\mathrm{\small modelview}}= \mathtt{I}\,\mathtt{T}_t\,\mathtt{T}_r\,\mathtt{T}_s $

    $\underline{\tilde{\mathbf{P}}} = \mathtt{T}_{\mathrm{\small modelview}} \, \underline{\mathbf{P}}$

Rotationen in 3D: Eulerwinkel

  • Um eine beliebige Rotation auszuführen, können die Rotationen um verschiedene Achsen hintereinander ausgeführt werden
  • Hier sind im Prinzip beliebige Reihenfolgen möglich z.B. zunächst um die $x$-Achse, dann um die unbewegte $y$-Achse und letztendlich um die unbewegte $z$-Achse
    $\underline{\tilde{\mathbf{P}}} = \mathtt{T}_{r_z} \mathtt{T}_{r_y} \mathtt{T}_{r_x} \, \underline{\mathbf{P}}$
  • Zu beachten ist, dass die Reihenfolge im OpenGL-Code wegen der Multiplikation von rechts genau umgekehrt ist:
    // rotate around z
    glRotatef(rot1, 0.0, 0.0, 1.0);
    // rotate around y
    glRotatef(rot2, 0.0, 1.0, 0.0);
    // rotate around x
    glRotatef(rot3, 1.0, 0.0, 0.0);  
    

Rotationen in 3D: Eulerwinkel

airplane
$x$
$y$
$z$
  • Die Transformation $\underline{\tilde{\mathbf{P}}} = \mathtt{T}_{r_z} \mathtt{T}_{r_y} \mathtt{T}_{r_x} \, \underline{\mathbf{P}}$ kann jedoch auch anderes interpretiert werden, wenn die Rotationsachsen nicht statisch sind, sondern mit rotiert werden
  • Bei mitdrehenden Achsen kann die Formel von links nach rechts interpretiert werden: Rotation zunächst um die $z$-Achse, dann um die mitgedrehte $y$-Achse und letztendlich um die mitgedrehte $x$-Achse
  • Diese Reihenfolge und Denkweise ist z.B. in der Luftfahrt gebräuchlich. Das Bezugssystem ist das Flugzeug, welches sich immer mitdreht: 1. gieren (um $z$), 2. nicken (um mitgedrehtes $y$), 3. rollen (um mitgedrehtes $x$)

Rotationen in 3D: Eulerwinkel

  • Da sich die Achsen mitdrehen, kann es auch Sinn machen, mehrfach um die gleiche (mitgedrehte) Achse zu rotieren.
  • Eine beliebte Kombination ist die sogenannte "$x$-Konvention" (auch "313-Konvention" genannt):
    $\underline{\tilde{\mathbf{P}}} = \mathtt{T}_{r_z} \mathtt{T}_{r_x} \mathtt{T}_{r_z} \, \underline{\mathbf{P}}$
  • Achtung: Wird für dieses Beispiel bei $\mathtt{T}_{r_x}$ um $\alpha = 0$ oder $180$ Grad gedreht, sind erste und letzte Drehachse parallel und ein Freiheitsgrad fällt weg
  • Dies wird "Gimbal Lock" genannt und ist ein allgemeines Problem von Eulerwinkeln (nicht nur bei der 313-Konvention). Ein Gimbal Lock führte z.B. zu Problemen bei der Apollo 11 Mission

Eulerwinkel / Gimbal Lock Demonstration

opengl_gimballock

Eulerwinkel / Gimbal Lock Demonstration

class Renderer {

public:
  float rot1;
  float rot2;
  float rot3;

public:
  Renderer() : rot1(0.0),  rot2(0.0),  rot3(0.0) {}

public:
  void display() {
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    
    // view scene from the side
    glTranslatef(0.0,0.0,-3.0);
    glRotatef( -45.0f, 0.0, 0.0, 1.0);
    glRotatef( -45.0f, 0.0, 1.0, 0.0);
    glRotatef( 135.0f, 1.0, 0.0, 0.0);

    // rotate around z
    glRotatef(rot1, 0.0, 0.0, 1.0);
    glColor3f(0.0f, 0.0f, 1.0f);
    drawCoordinateAxisZ();

    // rotate around local y
    glRotatef(rot2, 0.0, 1.0, 0.0);
    glColor3f(0.0f, 1.0f, 0.0f);
    drawCoordinateAxisY();

    // rotate around local x
    glRotatef(rot3, 1.0, 0.0, 0.0);
    glColor3f(1.0f, 0.0f, 0.0f);
    drawCoordinateAxisX();

    // draw the plane in the local coordinate system
    drawToyPlane();

    glFlush();
  }

private:
  void drawCoordinateAxisZ() {
    glBegin(GL_LINE_LOOP); // circle in x-y plane
    for(int a=0; a<360; a+=10) {
      float angle = M_PI / 180.0f * a;
      glVertex3f(cos(angle), sin(angle), 0.0);
    }
    glEnd();

    glBegin(GL_LINES);
    glVertex3f(0.9f, 0.0f, 0.0f); // x-axis
    glVertex3f(1.0f, 0.0f, 0.0f);
    glVertex3f(0.0f, 0.9f, 0.0f); // y-axis
    glVertex3f(0.0f, 1.0f, 0.0f);
    glVertex3f(0.0f, 0.0f,-1.0f); // z-axis
    glVertex3f(0.0f, 0.0f, 1.0f);
    glEnd();

    glBegin(GL_TRIANGLES); // z-axis tip
    glVertex3f(0.0f,-0.1f, 0.9f);
    glVertex3f(0.0f, 0.0f, 1.0f);
    glVertex3f(0.0f, 0.1f, 0.9f);
    glEnd();
  }

  void drawCoordinateAxisX() {
    glPushMatrix();
    glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
    drawCoordinateAxisZ();
    glPopMatrix();
  }

  void drawCoordinateAxisY() {
    glPushMatrix();
    glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
    drawCoordinateAxisZ();
    glPopMatrix();
  }
  ...
};

Rotationsmatrizen

  • Die Transformation um die einzelnen Achsen kann auch zu einer Rotationsmatrix zusammengefasst werden, z.B.,
    $\underline{\tilde{\mathbf{P}}} = \underbrace{\mathtt{T}_{r_z} \mathtt{T}_{r_y} \mathtt{T}_{r_x}}_{\mathtt{T_r}} \, \underline{\mathbf{P}}$
  • Dabei hat die Rotationsmatrix $\mathtt{T_r}$ die allgemeine Form
    $\mathtt{T_r} = \begin{bmatrix} r_{11} & r_{12}& r_{13} & 0 \\ r_{21} & r_{22}& r_{23} & 0 \\ r_{31} & r_{32}& r_{33} & 0 \\ 0 & 0 & 0 &1 \\ \end{bmatrix} = \begin{bmatrix} \mathtt{R} & 0 \\ \mathbf{0} & 1 \end{bmatrix} $
  • Die $3 \times 3$ Matrix $\mathtt{R}$ beschreibt eine Rotationsmatrix, wenn
    • Längen und Winkel erhalten bleiben, d.h. es gilt für das Skalarprodukt
      $\langle \mathbf{a}, \mathbf{b}\rangle = \langle \mathtt{R}\,\mathbf{a}, \mathtt{R}\,\mathbf{b}\rangle \quad \forall \mathbf{a}, \mathbf{b} \in \mathbb{R}^3$
    • die Orientierungen der Basisvektoren $\tilde{\mathbf{b}}_x, \tilde{\mathbf{b}}_y, \tilde{\mathbf{b}}_z$ erhalten bleiben
      $\det \mathtt{R} = \det \begin{bmatrix}\tilde{\mathbf{b}}_x & \tilde{\mathbf{b}}_y & \tilde{\mathbf{b}}_z \end{bmatrix} = 1$

Eigenschaften von Rotationsmatrizen

  • Die Basisvektoren $\tilde{\mathbf{b}}_x, \tilde{\mathbf{b}}_y, \tilde{\mathbf{b}}_z$ sind orthonormal
  • Rotationsmatrizen sind leicht invertierbar durch Transponieren der Matrix
    $\mathtt{R}^{-1} = \mathtt{R}^\top$
  • Damit gilt auch
    $\mathtt{R}^{-1} \mathtt{R}= \mathtt{R}^\top \mathtt{R} = \mathtt{I}_{3 \times 3}$
  • Rotationen sind nicht kommutativ, d.h. im Allgemeinen gilt
    $\mathtt{R}_a \mathtt{R}_b \ne \mathtt{R}_b \mathtt{R}_a$

Quaternionen

Quaternionen

  • Eulerwinkel sind leicht zu implementieren und zu verstehen
  • Allerdings gibt es Unstetigkeiten und es kann zu einem Gimbal Lock kommen
  • Ein weiterer Nachteil ist, dass es relativ schwer ist, von einer gegebenen Rotationsmatrix die erzeugenden Eulerwinkel auszurechnen (typischerweise nicht eindeutig)
  • Abhilfe schaffen sogenannte Quaternionen

Rotation um eine beliebige Achse

  • Ein Schritt hin zum Verständnis von Quaternionen ist die Beschreibung einer Rotation um eine beliebige gegebene Achse $\mathbf{n}$ (mit $|\mathbf{n}|=1$) um einen Winkel $\alpha$
rot_around_n
$x$
$y$
$z$
$\mathbf{n}$
$\alpha$
$\mathbf{v}$
$\mathbf{v}_n$
$\mathbf{n} \times \mathbf{v}$
$\mathbf{v} - \mathbf{v}_n$

mit $\mathbf{v}_n = (\mathbf{v}^\top \mathbf{n})\, \mathbf{n}$ gilt $\tilde{\mathbf{v}} = \mathbf{v}_n + (\mathbf{v} - \mathbf{v}_n) \cos \alpha + (\mathbf{n} \times \mathbf{v}) \sin \alpha$

Rotation um eine beliebige Achse

mit $\mathbf{v}_n = (\mathbf{v}^\top \mathbf{n})\, \mathbf{n} = (\mathbf{n}^\top \mathbf{v} )\, \mathbf{n} = (\mathbf{n} \mathbf{n}^\top) \mathbf{v}$ gilt:

$\begin{align} \tilde{\mathbf{v}} &= \mathbf{v}_n + (\mathbf{v} - \mathbf{v}_n) \cos \alpha + (\mathbf{n} \times \mathbf{v}) \sin \alpha\\ \tilde{\mathbf{v}} &= (\mathbf{n} \mathbf{n}^\top) \mathbf{v} + (\mathbf{v} - (\mathbf{n}\mathbf{n}^\top ) \mathbf{v}) \cos \alpha + ([\mathbf{n}]_\times \mathbf{v}) \sin \alpha\\ \tilde{\mathbf{v}} &= \mathtt{R} \mathbf{v} \end{align}$

wobei die resultierende $3 \times 3$ Rotationsmatrix eine Funktion von $\mathbf{n}$ und $\alpha$ ist, die sich berechnen lässt durch
$ \mathtt{R} = (\mathbf{n} \mathbf{n}^\top) + (\cos \alpha) (\mathbf{I}_{3\times 3} - (\mathbf{n} \mathbf{n}^\top)) + (\sin \alpha) [\mathbf{n}]_\times$

Die Rotationsmatrix hat also 4 Freiheitsgrade $\mathbf{n}=(n_x, n_y, n_z)$ und $\alpha$. Beziehungsweise, da gilt $|\mathbf{n}|=1$, gibt es eigentlich nur 3 Freiheitsgrade (äquivalent der Repräsentation mit Eulerwinkeln)

Quaternionen

  • Wichtiger Begründer der Theorie: William Rowan Hamilton (seit 1843)
  • Ein Quaternion $\mathbf{q}$ besteht aus 4 Komponenten
  • Die Komponenten werden meist in ein Skalar $s$ und einen Vektor $\mathbf{v}=(v_x, v_y, v_y)^\top$ aufgeteilt:

    $\mathbf{q} = \begin{pmatrix}q_1\\q_2\\ q_3\\ q_4\end{pmatrix} = \begin{pmatrix}s \\v_x \\ v_y \\ v_z\end{pmatrix} = (s, \mathbf{v}^\top)^\top$

  • Im Folgenden werden immer normierte Quaternionen verwendet, d.h. $|\mathbf{q}| = 1$ (wieder 3 Freiheitsgrade)

Quaternionen

  • Quaternionen können zur Repräsentation von Rotationen verwendet werden
  • Zur Darstellung einer Rotation um eine beliebige gegebene Achse $\mathbf{n}$ (mit $|\mathbf{n}|=1$) um einen Winkel $\alpha$ gilt:
    $\mathbf{q} = \begin{pmatrix}s\\v_x\\ v_y\\ v_z\end{pmatrix} = \begin{pmatrix}\cos \frac{\alpha}{2} \\n_x \sin \frac{\alpha}{2} \\ n_y \sin \frac{\alpha}{2} \\ n_z \sin \frac{\alpha}{2} \end{pmatrix} = (\cos \frac{\alpha}{2}, (\sin \frac{\alpha}{2}) \mathbf{n}^\top)^\top$

Quaternionen-Multiplikation

  • Für die Multiplikation von Quaternionen gilt:
    $\begin{align}\mathbf{q} \mathbf{q}' &= \begin{pmatrix} s\, s'- v_x v'_x - v_y v'_y-v_z v'_z \\ s v'_x + v_x s' + v_y v'_z - v_z v'_y\\ s v'_y + v_y s' + v_z v'_x - v_x v'_z\\ s v'_z + v_z s' + v_x v'_y - v_y v'_x\end{pmatrix}\\ &=(s \, s'- \mathbf{v}^\top \mathbf{v}' , (s \mathbf{v}' + s'\mathbf{v}+ \mathbf{v} \times \mathbf{v}')^\top )^\top \end{align}$
  • Genau wie die Multiplikation von Matrizen, ist die Quaternionen-Multiplikation nicht kommutativ
  • Die Quaternionen-Multiplikation kann zur Verkettung von Rotationen verwendet werden (entsprechend der Matrix-Multiplikation bei Rotationsmatrizen)

Quaternionen-Multiplikation

  • Durch weitere Umformungen und geschicktes Vorberechnen mehrfach benötigter Ausdrücke kann die Quaternionen-Multiplikation sehr effizient implementiert werden:
Quaternion fastmul(Quaternion ql, Quaternion qr) {
double s[9], t;
s[0] = (ql.vz-ql.vy)*(qr.vy-qr.vz); s[1] = (ql.s +ql.vx)*(qr.s +qr.vx);
s[2] = (ql.s -ql.vx)*(qr.vy+qr.vz); s[3] = (ql.vz+ql.vy)*(qr.s -qr.vx);
s[4] = (ql.vz-ql.vx)*(qr.vx-qr.vy); s[5] = (ql.vz+ql.vx)*(qr.vx+qr.vy);
s[6] = (ql.s +ql.vy)*(qr.s -qr.vz); s[7] = (ql.s -ql.vy)*(qr.s +qr.vz);
s[8] = s[5]+s[6]+s[7];
t = (s[4]+s[8])*0.5;
return Quaternion(s[0]+t-s[5], s[1]+t-s[8], s[2]+t-s[7], s[3]+t-s[6]);
} 

Quaternionen-Multiplikation

  • Eine Inversion kann durch die Konjugation des Quaternions erfolgen:
    $\mathbf{q}^{-1} = (s, -\mathbf{v}^\top)^\top$
  • Das neutrale Element bezüglich der Quaternionen-Multiplikation ist:
    $\mathbf{1} = (1, \mathbf{0}^\top)^\top$

Quaternionen

  • Ein Punkt $\mathbf{p}$, der mit einem Quaternion rotiert werden soll, muss zunächst ebenfalls als Quaternionen dargestellt werden:
    $\mathbf{p} = \begin{pmatrix}x \\ y \\ z \end{pmatrix} \rightarrow \mathbf{p}_q = \begin{pmatrix}0 \\ x \\ y \\ z \end{pmatrix}$
  • Dann gilt für den transformierten Punkt $\tilde{\mathbf{p}}_q$:
    $\tilde{\mathbf{p}}_q = \mathbf{q}\, \mathbf{p}_q \,\mathbf{q}^{-1} $

Quaternionen

  • Ein Quaternion $\mathbf{q}= (s, x, y, z)^\top$ kann in eine Rotationsmatrix $\mathtt{R}$ konvertiert werden:
    $\begin{bmatrix} 1-2y^2-2z^2 & 2xy-2sz& 2xz+2ys \\ 2xy+2sz & 1-2x^2-2z^2& 2yz-2sx \\ 2xz-2sy & 2yz+2sx& 1-2x^2-2y^2 \\ \end{bmatrix} $

Quaternionen: Beispiel 1

  • gesucht: Rotation, die den Einheitsvektor $\mathbf{b}$ auf den Einheitsvektor $\tilde{\mathbf{b}}$ dreht
  • Lösung:
    • Bestimmen der Rotationsachse mit dem Kreuzprodukt: $\mathbf{n}= \mathbf{b} \times \tilde{\mathbf{b}}$
    • Bestimmen des Rotationswinkels $\alpha$ mit dem Skalarprodukt: $\mathbf{b}^\top \tilde{\mathbf{b}}=\cos \alpha$
    • Das Quaternion $\mathbf{q} = (\cos \frac{\alpha}{2}, (\sin \frac{\alpha}{2}) \mathbf{n}^\top)^\top$ beschreibt die gesuchte Rotation

Quaternionen: Beispiel 2

  • Gesucht: Position des Punktes $\mathbf{p}=(x,y,z)^\top$ nach einer Rotation um die Achse $\mathbf{n}$ mit dem Winkel $\alpha$
  • Lösung:
    • Rotationsquaternion bestimmen: $\mathbf{q} = (\cos \frac{\alpha}{2}, (\sin \frac{\alpha}{2}) \mathbf{n}^\top)^\top$
    • Quaternionen-Multiplikation anwenden:
      $\tilde{\mathbf{p}}_q = \mathbf{q}\, \mathbf{p}_q \,\mathbf{q}^{-1} = \mathbf{q}\, (0, x, y, z)^\top \,\mathbf{q}^{-1} $
    • Das resultierende Quaternion $\tilde{\mathbf{p}}_q$ wieder als kartesischen Punkt $\tilde{\mathbf{p}}$ schreiben, indem die letzten drei Komponenten extrahiert werden.

Interpolation von Rotationsmatrizen

  • Gegeben: Zwei Rotationsmatrizen, $\mathtt{R}_{0}$ zum Zeitpunkt $t=0$ und $\mathtt{R}_{1}$ zum Zeitpunkt $t=1$
  • Kann eine zeitliche lineare Interpolation der Rotation folgendermaßen erreichen werden?
    $\mathtt{R}(t) = (1-t) \, \mathtt{R}_0 + t \, \mathtt{R}_1$ mit $t \in [0, 1]$
  • Nein!
  • Stattdessen lineare Interpolation des Rotationswinkels
    $\alpha(t) = (1-t)\, \alpha_0 + t\, \alpha_1$
    und anschließend $\alpha(t)$ mit Quaternionen (oder Eulerwinkeln) verwenden

Falsche Interpolation von Rotationsmatrizen

rotation_interpolation

Falsche Interpolation von Rotationsmatrizen

class Renderer {
public:
  Renderer() : t(0.0) {}

public:
  void display() {
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    // view scene from the side
    glTranslatef(0.0,0.0,-3.0);
    glRotatef( -45.0f, 0.0, 0.0, 1.0);
    glRotatef( -45.0f, 0.0, 1.0, 0.0);
    glRotatef( 135.0f, 1.0, 0.0, 0.0);

    if(true) {
      // interpolate rotation matrices, which is wrong
      float r0[16];
      float r1[16];
      float rt[16];
      glPushMatrix(); // save for later use
      glLoadIdentity();
      glGetFloatv(GL_MODELVIEW_MATRIX, r0);
      glRotatef(180.0f, 0.0, 0.0, 1.0); // rotate around z
      glGetFloatv(GL_MODELVIEW_MATRIX, r1);
      glPopMatrix(); // restore
      for(unsigned i=0; i < 16; i++) {
        rt[i] = (1-t) * r0[i] + t * r1[i]; //interpolate
      }
      glMultMatrixf(rt); // apply matrix
    }else{
      // interpolate rotation angle, which is correct
      glRotatef(t*180.0f, 0.0, 0.0, 1.0); // rotate around z
    }
    glColor3f(0.0f, 0.0f, 1.0f);
    drawCoordinateAxisZ();
    glColor3f(0.0f, 1.0f, 0.0f);
    drawCoordinateAxisY();
    glColor3f(1.0f, 0.0f, 0.0f);
    drawCoordinateAxisX();
 
    glFlush();
  }
  ...
 };

Gibt es Fragen?

questions

Anregungen oder Verbesserungsvorschläge können auch gerne per E-mail an mich gesendet werden: Kontakt

Weitere Vorlesungsfolien

Folien auf Englisch (Slides in English)