Mam prostą realizację silnika gry encja / komponent.
Komponent Transform ma metody ustalania pozycji lokalnej, rotacji lokalnej, pozycji globalnej i rotacji globalnej.
Jeśli transformacja jest ustalana jako nowa pozycja globalna, wówczas zmienia się także pozycja lokalna, aby zaktualizować pozycję lokalną w takim przypadku po prostu stosuję bieżącą lokalną macierz transformacji do macierzy świata transformacji rodzica.
Do tego czasu nie mam problemów, mogę uzyskać zaktualizowaną macierz transformacji lokalnej.
Ale walczę o to, jak zaktualizować lokalną wartość położenia i obrotu w transformacji. Jedynym rozwiązaniem, które mam na myśli, jest wydobycie wartości translacji i rotacji z localMatrix transformacji.
Do tłumaczenia jest to dość łatwe - po prostu biorę wartości z 4 kolumny. ale co z rotacją?
Jak wyodrębnić kąty eulera z macierzy transformacji?
Czy takie rozwiązanie jest właściwe ?:
Aby znaleźć obrót wokół osi Z, możemy znaleźć różnicę między wektorem osi X localTransform i wektorem osi X rodzica.localTransform i zapisać wynik w Delta, a następnie: localRotation.z = atan2 (Delta.y, Delta .x);
To samo dotyczy obrotu wokół X i Y, wystarczy zamienić oś.
Mike Day ma świetny opis tego procesu: https://d3cw3dd2w32x2b.cloudfront.net/wp-content/uploads/2012/07/euler-angles1.pdf
Jest również teraz zaimplementowany w glm, począwszy od wersji 0.9.7.0, 02/08/2015. Sprawdź wdrożenie .
Aby zrozumieć matematykę, powinieneś przyjrzeć się wartościom, które znajdują się w macierzy rotacji. Ponadto musisz znać kolejność stosowania rotacji, aby utworzyć matrycę w celu prawidłowego wyodrębnienia wartości.
Macierz obrotu z kątów Eulera powstaje przez połączenie obrotów wokół osi x, y i z. Na przykład obracanie o θ stopni wokół Z można wykonać za pomocą macierzy
Istnieją podobne macierze do obracania się wokół osi X i Y:
Możemy pomnożyć te macierze razem, aby utworzyć jedną macierz, która jest wynikiem wszystkich trzech rotacji. Należy zauważyć, że kolejność mnożenia tych macierzy jest ważna, ponieważ mnożenie macierzy nie jest przemienne . To znaczy że
Rx*Ry*Rz ≠ Rz*Ry*Rx
. Rozważmy jeden możliwy porządek obrotu, zyx. Po połączeniu trzech macierzy powstaje macierz, która wygląda następująco:gdzie
Cx
jest cosinusx
kąta obrotu,Sx
sinusx
kąta obrotu itp.Teraz wyzwaniem jest wyodrębnienie oryginału
x
,y
orazz
wartości, które poszedł do matrycy.Najpierw ustalmy
x
kąt. Jeśli znamysin(x)
icos(x)
, możemy użyć funkcji odwrotnej stycznej,atan2
aby przywrócić nam kąt. Niestety wartości te nie pojawiają się same w naszej matrycy. Ale jeśli przyjrzymy się bliżej elementomM[1][2]
iM[2][2]
zobaczymy, że wiemy-sin(x)*cos(y)
równie dobrzecos(x)*cos(y)
. Ponieważ funkcja styczna jest stosunkiem przeciwnych i sąsiednich boków trójkąta, skalowanie obu wartości o tę samą wartość (w tym przypadkucos(y)
) da ten sam wynik. A zatem,Teraz spróbujmy zdobyć
y
. Wiemysin(y)
zM[0][2]
. Gdybyśmy mieli cos (y), moglibyśmy użyćatan2
ponownie, ale nie mamy tej wartości w naszej macierzy. Jednak ze względu na tożsamość pitagorejską wiemy, że:Możemy więc obliczyć
y
:Na koniec musimy obliczyć
z
. Tutaj podejście Mike'a Day różni się od poprzedniej odpowiedzi. Ponieważ w tym momencie znamy wielkośćx
iy
obrót, możemy zbudować macierz obrotu XY i znaleźć wielkośćz
obrotu niezbędną do dopasowania do macierzy docelowej.RxRy
Matryca wygląda tak:Ponieważ wiemy, że
RxRy
*Rz
jest równe naszej macierzy wejściowejM
, możemy użyć tej macierzy, aby wrócić doRz
:Odwrotność macierzy rotacji jest jego transpozycji , dzięki czemu mogą się rozszerzyć do tego:
Możemy teraz rozwiązać dla
sinZ
icosZ
przez mnożenie macierzy. Musimy tylko obliczyć elementy[1][0]
i[1][1]
.Oto pełna implementacja w celach informacyjnych:
źródło
M[1][3]
pomocąM[1][2]
i zaM[2][3]
pomocąM[2][2]
.