Wenn ich mir eine ausgefüllte Matrix in meinem Programm ansehe, sehe ich die Übersetzungskomponenten, die das 4., 8. und 12. Element belegen.
Bevor ich beginne, ist es wichtig zu verstehen: Dies bedeutet , dass Ihre Matrizen Eklat . Deshalb beantworten Sie diese Frage:
Meine Spalten-Haupt-WVP-Matrix wird erfolgreich verwendet, um Scheitelpunkte mit dem HLSL-Aufruf zu transformieren: mul (Vektor, Matrix), was dazu führen sollte, dass der Vektor als Zeilen-Haupt behandelt wird. Wie kann also die von meiner Mathematikbibliothek bereitgestellte Spalten-Hauptmatrix funktionieren?
ist ganz einfach: Ihre Matrizen sind Zeilenmajor.
So viele Menschen verwenden Zeilenmajor- oder transponierte Matrizen, dass sie vergessen, dass Matrizen nicht auf natürliche Weise so ausgerichtet sind. Sie sehen also eine Übersetzungsmatrix wie folgt:
1 0 0 0
0 1 0 0
0 0 1 0
x y z 1
Dies ist eine transponierte Übersetzungsmatrix . So sieht eine normale Übersetzungsmatrix nicht aus. Die Übersetzung erfolgt in der 4. Spalte , nicht in der vierten Zeile. Manchmal sieht man das sogar in Lehrbüchern, was völliger Müll ist.
Es ist leicht zu erkennen, ob eine Matrix in einem Array Zeilen- oder Spaltenmajor ist. Wenn es sich um Zeilenmajor handelt, wird die Übersetzung in den Indizes 3, 7 und 11 gespeichert. Wenn es sich um eine Spalte handelt, wird die Übersetzung in den Indizes 12, 13 und 14 gespeichert. Null-Basis-Indizes natürlich.
Ihre Verwirrung rührt von der Annahme her, dass Sie Spalten-Hauptmatrizen verwenden, obwohl Sie tatsächlich Zeilen-Hauptmatrizen verwenden.
Die Aussage, dass Zeile gegen Spalte Major nur eine Notationskonvention ist, ist völlig richtig. Die Mechanismen der Matrixmultiplikation und der Matrix / Vektor-Multiplikation sind unabhängig von der Konvention gleich.
Was sich ändert, ist die Bedeutung der Ergebnisse.
Eine 4x4-Matrix ist schließlich nur ein 4x4-Zahlenraster. Es muss nicht haben zu einer Änderung bezieht sich das Koordinatensystem. Sobald Sie jedoch einer bestimmten Matrix eine Bedeutung zugewiesen haben , müssen Sie wissen, was darin gespeichert ist und wie Sie sie verwenden.
Nehmen Sie die Übersetzungsmatrix, die ich Ihnen oben gezeigt habe. Das ist eine gültige Matrix. Sie können diese Matrix auf float[16]
zwei Arten speichern :
float row_major_t[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1};
float column_major_t[16] = {1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z, 0, 0, 0, 1};
Ich sagte jedoch, dass diese Übersetzungsmatrix falsch ist, weil die Übersetzung am falschen Ort ist. Ich habe ausdrücklich gesagt, dass es relativ zur Standardkonvention zum Erstellen von Übersetzungsmatrizen transponiert ist, die so aussehen sollte:
1 0 0 x
0 1 0 y
0 0 1 z
0 0 0 1
Schauen wir uns an, wie diese gespeichert werden:
float row_major[16] = {1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z, 0, 0, 0, 1};
float column_major[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, x, y, z, 1};
Beachten Sie, dass column_major
ist genau das gleiche wie row_major_t
. Wenn wir also eine richtige Übersetzungsmatrix nehmen und als Spaltenmajor speichern, ist dies dasselbe wie das Transponieren dieser Matrix und das Speichern als Zeilenmajor.
Das ist es, was nur als Notationskonvention gemeint ist. Es gibt wirklich zwei Arten von Konventionen: Speicher und Transposition. Der Speicher ist Spalte gegen Zeile Haupt, während die Transposition normal gegen transponiert ist.
Wenn Sie eine Matrix haben, die in Zeilenreihenfolge generiert wurde, können Sie den gleichen Effekt erzielen, indem Sie das Spalten-Hauptäquivalent dieser Matrix transponieren. Und umgekehrt.
Die Matrixmultiplikation kann nur auf eine Weise erfolgen: Bei zwei Matrizen in einer bestimmten Reihenfolge multiplizieren Sie bestimmte Werte miteinander und speichern die Ergebnisse. Nun, A*B != B*A
aber der tatsächliche Quellcode für A*B
ist der gleiche wie der Code für B*A
. Beide führen denselben Code aus, um die Ausgabe zu berechnen.
Dem Matrixmultiplikationscode ist es egal, ob die Matrizen zufällig in Spalten-Haupt- oder Zeilen-Hauptreihenfolge gespeichert sind.
Das Gleiche gilt nicht für die Vektor / Matrix-Multiplikation. Und hier ist warum.
Vektor / Matrix-Multiplikation ist eine Lüge; es kann nicht gemacht werden. Sie können jedoch eine Matrix mit einer anderen Matrix multiplizieren. Wenn Sie also so tun, als wäre ein Vektor eine Matrix, können Sie effektiv eine Vektor / Matrix-Multiplikation durchführen, indem Sie einfach eine Matrix / Matrix-Multiplikation durchführen.
Ein 4D-Vektor kann als Spaltenvektor oder Zeilenvektor betrachtet werden. Das heißt, ein 4D-Vektor kann als 4x1-Matrix (denken Sie daran: In der Matrixnotation steht die Zeilenanzahl an erster Stelle) oder als 1x4-Matrix betrachtet werden.
Aber hier ist die Sache: Bei zwei Matrizen A und B A*B
wird nur definiert, wenn die Anzahl der Spalten von A der Anzahl der Zeilen von B entspricht. Wenn also A unsere 4x4-Matrix ist, muss B eine Matrix mit 4 Zeilen sein drin. Daher können Sie nicht ausführen A*x
, wenn x ein Zeilenvektor ist . Ebenso können Sie nicht ausführen, x*A
wenn x ein Spaltenvektor ist.
Aus diesem Grund gehen die meisten Matrix-Mathematikbibliotheken von dieser Annahme aus: Wenn Sie einen Vektor mit einer Matrix multiplizieren, möchten Sie wirklich die Multiplikation durchführen, die tatsächlich funktioniert , und nicht die, die keinen Sinn ergibt.
Definieren wir für jeden 4D-Vektor x Folgendes. C
so ist die Spaltenvektormatrixform , und wird der Zeilenvektor seines Matrix - Form . Wenn dies gegeben ist, repräsentiert für jede 4 × 4-Matrix A die Matrix, die A mit dem Spaltenvektor multipliziert . Und stellt eine Matrix dar, die den Zeilenvektor mit A multipliziert .x
R
x
A*C
x
R*A
x
Wenn wir dies jedoch mit strenger Matrixmathematik betrachten, sehen wir, dass diese nicht äquivalent sind . R*A
kann nicht dasselbe sein wie A*C
. Dies liegt daran, dass ein Zeilenvektor nicht dasselbe ist wie ein Spaltenvektor. Sie sind nicht die gleiche Matrix, daher liefern sie nicht die gleichen Ergebnisse.
Sie sind jedoch in einer Hinsicht miteinander verbunden. Es ist wahr, dass R != C
. Allerdings ist es auch wahr , dass , wo T die Transponierung ist. Die beiden Matrizen sind Transponierte voneinander.R = CT
Hier ist eine lustige Tatsache. Da Vektoren als Matrizen behandelt werden, haben auch sie eine Frage zur Speicherung von Spalten und Zeilen. Das Problem ist, dass beide gleich aussehen . Das Array der Floats ist das gleiche, sodass Sie den Unterschied zwischen R und C nicht nur anhand der Daten erkennen können. Der einzige Weg, um den Unterschied zu erkennen, besteht darin, wie sie verwendet werden.
Wenn Sie zwei Matrizen A und B haben und A als Zeilenmajor und B als Spaltenmajor gespeichert ist, ist das Multiplizieren dieser Matrizen völlig bedeutungslos . Sie bekommen dadurch Unsinn. Nicht wirklich. Mathematisch ist das, was Sie bekommen, das Äquivalent zu tun . Oder ; Sie sind mathematisch identisch.AT*B
A*BT
Daher ist eine Matrixmultiplikation nur dann sinnvoll, wenn die beiden Matrizen (und denken Sie daran: Vektor / Matrix-Multiplikation ist nur eine Matrixmultiplikation) in derselben Hauptreihenfolge gespeichert sind.
Ist also ein Vektor Spaltenmajor oder Zeilenmajor? Es ist beides und keines von beiden, wie bereits erwähnt. Es ist nur dann Spaltenmajor, wenn es als Spaltenmatrix verwendet wird, und es ist Zeilenmajor, wenn es als Zeilenmatrix verwendet wird.
Wenn Sie also eine Matrix A haben, die Spalte Major ist, x*A
bedeutet dies ... nichts. Nun, es bedeutet wieder , aber das ist nicht das, was Sie wirklich wollten. In ähnlicher Weise erfolgt die transponierte Multiplikation, wenn sie zeilengroß ist.x*AT
A*x
A
Daher ändert sich die Reihenfolge der Vektor / Matrix-Multiplikation abhängig von Ihrer Hauptreihenfolge der Daten (und davon, ob Sie transponierte Matrizen verwenden).
Warum im folgenden Codeausschnitt r! = R2
Weil dein Code kaputt und fehlerhaft ist. Mathematisch , . Wenn Sie dieses Ergebnis nicht erhalten, ist entweder Ihr Gleichheitstest falsch (Gleitkommapräzisionsprobleme) oder Ihr Matrixmultiplikationscode ist fehlerhaft.A * (B * C) == (CT * BT) * AT
warum ist pos3! = pos für
Weil das keinen Sinn ergibt. Der einzige Weg , um wahr zu sein, wäre, wenn . Und das gilt nur für symmetrische Matrizen.A * t == AT * t
A == AT