jeśli spojrzę na zapełnioną macierz w moim programie, widzę, że komponenty tłumaczenia zajmują 4, 8 i 12 element.
Zanim zacznę, ważne jest, aby zrozumieć: oznacza to, że macierze są wiersze główne . Dlatego odpowiadasz na to pytanie:
moja główna matryca WVP głównej kolumny jest z powodzeniem używana do transformacji wierzchołków za pomocą wywołania HLSL: mul (wektor, macierz), co powinno spowodować, że wektor będzie traktowany jako główny wiersz, więc jak może działać macierz główna kolumny dostarczona przez moją bibliotekę matematyczną?
jest dość proste: macierze są ważniejsze od rzędów.
Tak wiele osób używa matryc głównych lub transponowanych, że zapominają, że macierze nie są w ten sposób naturalnie zorientowane. Widzą więc macierz tłumaczeń w następujący sposób:
1 0 0 0
0 1 0 0
0 0 1 0
x y z 1
To jest transponowana macierz tłumaczeń . Nie tak wygląda normalna macierz tłumaczeń. Tłumaczenie znajduje się w czwartej kolumnie , a nie w czwartym wierszu. Czasami widać to nawet w podręcznikach, co jest kompletnym śmieciem.
Łatwo jest ustalić, czy macierz w tablicy jest rzędem czy kolumną. Jeśli jest to wiersz główny, tłumaczenie jest przechowywane w indeksach 3, 7 i 11. Jeśli jest to kolumna główna, tłumaczenie jest przechowywane w indeksach 12, 13 i 14. Oczywiście wskaźniki o zerowej podstawie.
Twoje zamieszanie wynika z przekonania, że używasz macierzy głównych kolumn, podczas gdy w rzeczywistości używasz macierzy głównych wierszy.
Stwierdzenie, że wiersz kontra główna kolumna jest tylko konwencją notacyjną, jest całkowicie prawdziwe. Mechanika mnożenia macierzy i mnożenia macierzy / wektora jest taka sama, niezależnie od konwencji.
Jakie zmiany mają znaczenie wyników.
W końcu macierz 4x4 to po prostu siatka liczb 4x4. Nie musi odnosić się do zmiany układu współrzędnych. Jednak po przypisaniu znaczenia konkretnej macierzy musisz teraz wiedzieć, co jest w niej przechowywane i jak z niej korzystać.
Weź matrycę tłumaczeń, którą pokazałem ci powyżej. To ważna matryca. Możesz przechowywać tę matrycę float[16]
na jeden z dwóch sposobów:
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};
Powiedziałem jednak, że ta matryca tłumaczeń jest błędna, ponieważ tłumaczenie znajduje się w niewłaściwym miejscu. Powiedziałem konkretnie, że jest transponowany w stosunku do standardowej konwencji, jak budować macierze tłumaczeń, które powinny wyglądać następująco:
1 0 0 x
0 1 0 y
0 0 1 z
0 0 0 1
Spójrzmy, jak są one przechowywane:
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};
Zauważ, że column_major
jest dokładnie taki sam jak row_major_t
. Tak więc, jeśli weźmiemy odpowiednią macierz translacji i zachowamy ją jako kolumnę główną, będzie to to samo, co transponowanie tej macierzy i przechowywanie jej jako major wiersza.
To właśnie oznacza bycie tylko konwencją notacyjną. Tak naprawdę istnieją dwa zestawy konwencji: pamięć i transpozycja. Pamięć jest kolumna kontra główny wiersz, a transpozycja jest normalna vs. transponowana.
Jeśli masz macierz, która została wygenerowana w kolejności major-wiersz, możesz uzyskać ten sam efekt, transponując równoważnik główny kolumny tej matrycy. I wzajemnie.
Mnożenie macierzy można wykonać tylko w jeden sposób: biorąc pod uwagę dwie macierze, w określonej kolejności, mnożymy pewne wartości razem i przechowujemy wyniki. Teraz, A*B != B*A
ale rzeczywisty kod źródłowy A*B
jest taki sam jak kod dla B*A
. Oba uruchamiają ten sam kod, aby obliczyć dane wyjściowe.
Kod mnożenia macierzy nie dba o to, czy macierze będą przechowywane w porządku kolumnowym, czy rządowym.
Tego samego nie można powiedzieć o mnożeniu wektora / macierzy. I oto dlaczego.
Mnożenie wektora / macierzy jest fałszem; nie da się tego zrobić. Jednakże, można pomnożyć macierz przez inną matrycę. Jeśli więc udajesz, że wektor jest macierzą, możesz efektywnie zwielokrotniać wektor / macierz, po prostu mnożąc macierz / macierz.
Wektor 4D można uznać za wektor kolumnowy lub wektor rzędowy. Oznacza to, że wektor 4D można traktować jako macierz 4x1 (pamiętaj: w notacji macierzowej liczba wierszy jest na pierwszym miejscu) lub macierz 1x4.
Ale o to chodzi: biorąc pod uwagę dwie macierze A i B, A*B
jest definiowane tylko wtedy, gdy liczba kolumn A jest taka sama jak liczba wierszy B. Dlatego jeśli A jest naszą macierzą 4x4, B musi być macierzą z 4 rzędami w tym. Dlatego nie można wykonać A*x
, gdzie x jest wektorem wiersza . Podobnie nie można wykonać, x*A
gdzie x jest wektorem kolumny.
Z tego powodu większość bibliotek matematycznych przyjmuje takie założenie: jeśli pomnożysz wektor razy macierz, naprawdę masz zamiar wykonać mnożenie, które faktycznie działa , a nie takie, które nie ma sensu.
Zdefiniujmy, dla dowolnego wektora 4D x: C
ma postać macierzy wektorów kolumnowych x
i R
ma postać macierzy wektorów rzędowych x
. Biorąc to pod uwagę, dla dowolnej macierzy 4x4 A A*C
reprezentuje macierz mnożącą A przez wektor kolumny x
. I R*A
reprezentuje macierz mnożącą wektor wiersza x
przez A.
Ale jeśli spojrzymy na to za pomocą ścisłej matematyki macierzowej, zobaczymy, że nie są one równoważne . R*A
nie może być taki sam jak A*C
. Jest tak, ponieważ wektor wiersza to nie to samo, co wektor kolumnowy. Nie są tą samą matrycą, więc nie dają takich samych wyników.
Są one jednak powiązane w jeden sposób. To prawda R != C
. Prawdą jest jednak również to , że tam, gdzie T jest operacją transpozycji. Dwie macierze są transponowane względem siebie.R = CT
Oto zabawny fakt. Ponieważ wektory są traktowane jako macierze, one również mają pytanie dotyczące przechowywania względem kolumny i wiersza. Problem polega na tym, że oba wyglądają tak samo . Tablica liczb zmiennoprzecinkowych jest taka sama, więc nie można odróżnić R i C tylko na podstawie danych. Tylko sposób odróżnić to od tego, jak są one wykorzystywane.
Jeśli masz jakieś dwie macierze A i B, a A jest przechowywane jako major-wiersz, a B jako major-kolumna, pomnożenie ich jest zupełnie bez znaczenia . W rezultacie dostajesz bzdury. Cóż, nie za bardzo. Matematycznie otrzymujesz ekwiwalent robienia . Lub ; są matematycznie identyczne.AT*B
A*BT
Dlatego mnożenie macierzy ma sens tylko wtedy, gdy dwie macierze (i pamiętaj: mnożenie macierzy / macierzy to tylko mnożenie macierzy) są przechowywane w tym samym głównym porządku.
A więc, czy wektor jest kolumna główna czy rzędowa? Jest to jedno i drugie, jak stwierdzono wcześniej. Jest to kolumna główna tylko wtedy, gdy jest używana jako matryca kolumnowa, i jest rzędem głównym, gdy jest używana jako matryca wierszowa.
Dlatego jeśli masz macierz A, która jest kolumną główną, x*A
oznacza ... nic. Znów oznacza to , ale nie tego naprawdę chciałeś. Podobnie transponuje mnożenie, jeśli jest rzędem głównym.x*AT
A*x
A
Dlatego kolejność wektor / mnożenia macierzy robi zmianom, w zależności od głównego porządkowania danych (i czy używasz transpozycji macierzy).
Dlaczego w poniższym fragmencie kodu r! = R2
Ponieważ Twój kod jest uszkodzony i zawiera błędy. Matematycznie . Jeśli nie otrzymasz tego wyniku, oznacza to, że test równości jest nieprawidłowy (problemy z precyzją zmiennoprzecinkową) lub kod mnożenia macierzy jest uszkodzony.A * (B * C) == (CT * BT) * AT
dlaczego pos3! = pos for
Ponieważ to nie ma sensu. Jedynym sposobem na prawdziwość byłoby, gdyby . Dotyczy to tylko matryc symetrycznych.A * t == AT * t
A == AT