Kongos rand() Tutorials, 2:
Vektoren und Matrizen
Vektoren und Matrizen spielen in der 3D Programmierung eine große
Rolle. Vektoren werden verwendet, um Punkte oder Bewegungen im Raum darzustellen.
Es gibt natürlich 2D und 3D Vektoren, hier besprechen wir jedoch nur 2D
Vektoren. 3D Vektoren funktionieren genau gleich.
Vektor Operationen
Ein 2D-Vektor setzt sich aus den x, y Koordinaten auseinander und sie werden
so geschrieben: (x/y). Ein Punkt ist ein Typ eines Vektors. Der Unterschied
zwischen einem Punkt und einem Vektor ist, das ein Punkt immer eine absolute
Position hat. Das heißt, er geht immer vom Koordinatenursprung (0/0) aus.
Ein Vektor muss jedoch nicht vom Ursprung ausgehen, sondern von irgendwo, wo
wir wollen.
Ein Beispiel: Ein Rechteck kann durch zwei Punkte repräsentiert werden,
nämlich den linken-oberen und den rechten-unteren. Jedoch kann man ein
Rechteck auch durch den linken-oberen Punkt und einem Vektor mit der Höhe
und Breite angeben.
Addition
Addition ist ganz einfach:
v1 + v2 = v3
(x1, y1) + (x2, y2) = (x1+x2, y1+y2)
Man addiert die X-Koordinaten und die Y-Koordinante um das Ergebnis, also den
Vektor zu bekommen.
Subtraktion
Die Subtraktion funktioniert genau wie die Addition.
v1 - v2 = v3
(x1, y1) - (x2, y2) = (x1-x2, y1-y2)
Das interessante bei der Subtraktion ist jedoch, dass v3 der Vektor von v2
zu v1 ist. Damit kann man den Vektor zwischen zwei Punkten berechnen.
Länge
Die Länge ergibt sich aus dem Satz von Pythagoras:
c2 = a2 + b2
c ist dabei die Länge der Hypotenuse, a und b die Länge der Kathete
bzw. Ankathete. In C++ müsste die Instruktion folgendermaßen lauten:
m = sqrt(x*x + y*y);
Normalisieren
Wenn man einen Vektor normalisiert, bedeutet es, dass dieser Vektor die Länge
1 bekommt und trotzdem noch in die gleiche Richtung zeigt.
vnormalisiert = ( x / |vold|, y / |vold| )
Wir dividieren einfach die Koordinaten (x,y) durch die Länge des Vektors
(|vold|). Und daraus entsteht der normalisierte Vektor.
Punktprodukt
Das Punktprodukt wird benötigt, um den Winkel zwischen zwei Vektoren auszurechnen.
Dabei ist das Punktprodukt gleich der Mulitplikation der Länge des ersten
Vektors mit der Länge des zweiten Vektors und dem Cosinus des Winkels zwischen
den Vektoren.
v1 · v2 = |v1| * |v2| * cos(ø)
Wir formen die Formel so um, dass wir den Winkel aus der Funktion bekommen:
ø = arccos( (v1 · v2) / (|v1| * |v2|) )
Und schon können wir den Winkel zwischen zwei Vektoren berechnen. Das
einzige was noch fehlt, ist die Berechnung des Punktprodukts. Die Formel lautet:
v1 · v2 = x1*x2 + y1*y2
Matrizen in der Direct3D-Programmierung
Unter Direct3D hat jedes Objekt ein eigenes (lokales) Koordinatensystem. Um
dieses Koordinatensystem ist meistenes das Objekt genau zentral positioniert.
Dabei besteht das Objekt nur aus Vektoren vom Koordinatenursprung zu seinem
bestimmte Platz. Um nun dieses Objekt auf den Bildschirm zu bringen, muss es
erst verschoben, rotiert und skaliert werden. Um diese Operationen wie das Rotieren
zu berechnen, verwendet man Matrizen.
Gebe es die Matrizen nicht, müssten wir mehrere Formeln verwenden, damit
das Objekt richtig positioniert wird. Das wären viele unnötige Berechnung,
die den Computer nur ausbremsen. Wir erstellen zwar mehrere Matrizen um das
Objekt zu bewegen, jedoch können wir diese miteinander multiplizieren.
Damit bleibt uns am Schluß nur noch eine einzige Matrix über. In
Direct3D schicken wir einfach unser Objekt mit dem lokalen Koordinatensystem
an das Direct3D Device und dieses berechnet intern all dies für uns. Wir
müssen Direct3D nur noch die Matrix bekannt geben.
Nun, eine Matrix ist nichts anderes als eine Tabelle. Unter Direct3D verwendet
man eine Matrix mit 4 Zeilen und 4 Spalten. Die sogennante 4x4 Matrix. Man kann
Matrizen addieren, multiplizieren,...
Die Eiheitsmatrix
Die Einheitsmatrix ist das neutrale Element unter den Matrizen. Sie ist wie
die 1, bei den normalen Zahlen.
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
Wenn wir irgendeine Matrix mit der Einheitsmatrix multiplizieren, kommt genau
wieder die erste Matrix heraus.
Verschieben eines Objektes
Die Verschiebung ist denkbar einfach. Wir addieren einfach zu jedem Vektor
eines Objekts die gewünschte Verschiebung. Wir wollen aber jeden Vektor
nicht direkt ändern, sondern wir erstellen eine Matrix, die wir am Schluß
Direct3D übergeben. Die Matrix sieht folgendermaßen aus:
1 0 0 0
0 1 0 0
0 0 1 0
tx ty tz 1
Wir erstellen einfach eine Einheitsmatrix und platzieren die Verschiebung auf
den Achsen in der letzten Zeile. Jeder Vektor den wir mit dieser Matrix multiplizieren,
wird nun korrekt um tx,ty,tz verschoben.
Rotieren eines Objektes
Um ein Objekt zu rotieren, benötigen wir für jede Achse genau eine
Matrix. In den folgenden Beispielen drehen wir jeweils das Objekt um a RAD (Achtung:
Direct3D rechnet in RAD nicht in Winkeln.):
x-Achse
1 0 0 0
0 cos(a) sin(a) 0
0 -sin(a) cos(a) 0
0 0 0 1
y-Achse
cos(a) 0 -sin(a) 0
0 1 0 0
sin(a) 0 cos(a) 0
0 0 0 1
z-Achse
cos(a) sin(a) 0 0
-sin(a) cos(a) 0 0
0 0 1 0
0 0 0 1
Jetzt haben wir aber 4 Matrizen. Um genau eine Matrix daraus zu machen, müssen
wir sie multiplizieren.
Multiplizieren
Das Multiplizieren von Matrizen ist schon nicht mehr so einfach. Man muss zwar
nur Addieren und Multiplizieren können, jedoch ist eine Multiplikation
einer 4x4 Matrix mit einer anderen Matrix ziemlich lang.
Wir wollen nun eine Matrix A mit einer Matrix B multiplizieren. Das Ergebnis
ist die Matrix C. Es gibt jedoch eine Regel bei der Multiplikation. Die Matrix
A muss so viele Spalten haben wie die Matrix B Zeilen hat. Da aber bei uns jede
Matrix 4 Spalten und 4 Zeilen hat, ist dies kein Problem.
Ein Eintrag Cij (i = Zeile, j = Spalte) in der Matrix C ergibtt sich dann aus
der Multiplikation der i'ten Zeile der Matrix A mit der j'ten Spalte der Matrix
B. Die Multiplikation der Zeile mit der Spalte geht wie folgt: Betrachten wir
die Zeile und die Spalte jeweils als einen Zahlenstrang, dann multiplizieren
wir die beiden ersten Elemente der Stränge miteinander , addieren dazu
die Multiplikation der beiden zweiten Elemente usw. Ein Beispiel mit 2x2 Matrizen:
|a11 a12| |b11 b12| |a11*b11 + a12*b21 a11*b12 + a12*b22|
* =
|a21 a22| |b21 b22| |a21*b11 + a22*b21 a21*b12 + a22*b22|
Hier kannst du dir jeweils eine
Klasse für Vektoren und Matrizen für Direct3D downloaden. Konnte
die Klassen leider nicht überprüfen. Wenn ihr Fehler findet, schickt
mir doch die optimierten Klassencodes an kongo@codeworx.org.
Die Matrix-Klasse ist auch noch nicht fertig. Einige Operatoren gehören
noch überladen. Achtung: Ich hab noch kein Bugfix gemacht. Da stecken sicher
viele Fehler drinnen.
Copyright (c) by Kongo
Bei Fragen, Beschwerden, Wünschen schreib an kongo@codeworx.org
Tutorial vom 30.06.2001