Jak mogę obracać się wokół dowolnego punktu w 3D (zamiast początku)?

15

Mam kilka modeli, które chcę obracać za pomocą czwartorzędów w normalny sposób, z wyjątkiem tego, że zamiast obrotu wokół początku chcę, aby został nieco przesunięty. Wiem, że nie mówisz w przestrzeni 3D, że obracasz się wokół punktu; mówisz, że obracasz się wokół osi. Wizualizuję to jako obracanie się wokół wektora, którego ogon nie jest ustawiony w miejscu pochodzenia.

Wszystkie transformacje afiniczne w moim silniku renderowania / fizyce są przechowywane za pomocą SQT (skala, kwaternion, tłumaczenie; pomysł zapożyczony z książki Game Engine Architecture ). Więc buduję macierz z każdej części z tych komponentów i przekazuję ją do modułu cieniującego wierzchołki. W tym systemie stosowane jest tłumaczenie, następnie skalowanie, a następnie obrót.

W jednym konkretnym przypadku muszę przetłumaczyć obiekt w przestrzeni świata, przeskalować go i obrócić wokół wierzchołka, który nie jest wyśrodkowany na lokalnym pochodzeniu obiektu.

Pytanie: Biorąc pod uwagę ograniczenia mojego obecnego systemu opisane powyżej, jak mogę osiągnąć lokalny obrót wyśrodkowany wokół punktu innego niż początek? Automatyczna opinia dla każdego, kto potrafi opisać, jak to zrobić, używając tylko matryc :)

notlesh
źródło
Czwarty opisują już obrót wokół dowolnej osi; czy masz problemy z budowaniem takiego czwartorzędu na podstawie danych, które posiadasz?
Martin Sojka,
3
Poważnie, czy ludzie, którzy głosowali za odpowiedziami, mogliby je przeczytać ? Podałem metodę, skuteczną formułę, a nawet demonstrację. Jednak jedyna pozytywna odpowiedź, podająca pewne cenne informacje (a także niektóre wyraźnie błędne informacje), nie zawiera żadnej z nich i nawet nie odpowiada na pytanie!
sam hocevar,
@MartinSojka, chodzi o dowolny punkt, a nie o dowolną oś.
notlesh,
@SamHocevar Obie odpowiedzi były pomocne. Wybrałem twój, ponieważ był dokładniejszy i pomógł mi znaleźć rozwiązanie. Dziękuję wam obu.
notlesh
Ach, przepraszam - pomyliłem to z Dual Quaternions (te też dostają tłumaczenie „za darmo”). Później napiszę, co miałem na myśli; być może inni uznaliby to za przydatne, zwłaszcza, że ​​możesz zredukować trzy komponenty do jednego - aczkolwiek nieco bardziej złożonego.
Martin Sojka,

Odpowiedzi:

17

W skrócie

Musisz tylko zmienić T w formularzu SQT.

Wymień wektor przesunięcia vz v' = v-invscale(p-invrotate(p))którym vjest początkowy wektor tłumaczenie, pjest punktem, wokół którego chcesz rotacja występuje, a invrotatei invscalesą odwrotności rotacji i skali.

Szybka demonstracja

Niech pbędzie punktem, w którym zastosujesz obrót r. Niech sbędą twoimi parametrami skalowania i vwektorem translacji. Ostateczna transformacja macierzowa jest T(p)R(r)T(-p)S(s)T(v)zamiast R(r)S(s)T(v).

Co chcesz to nowe parametry transformacji v', r'i s'tak, że transformacja matryca jest ostateczna R(r')S(s')T(v')i mamy:

T(p)R(r)T(-p)S(s)T(v) = R(r')S(s')T(v')

Zachowanie w nieskończoności wskazuje, że parametry obrotu i parametry skalowania nie mogą się zmienić (można to wykazać). Mamy więc r = r'i s = s'. Jedynym brakującym parametrem jest zatem v'nowy wektor tłumaczenia:

T(p)R(r)T(-p)S(s)T(v) = R(r)S(s)T(v')

Jeśli te macierze są równe, ich odwrotności są równe:

T(-v)S(-s)T(p)R(-r)T(-p) = T(-v')S(-s)R(-r)

Dotyczy to zwłaszcza pochodzenia O:

T(-v)S(-s)T(p)R(-r)T(-p)O = T(-v')S(-s)R(-r)O

Skalowanie i obracanie początku daje początek, dzięki czemu uzyskuje się:

T(-v)S(-s)T(p)R(-r)(-p) = -v'

v'to nowy wektor tłumaczenia, którego szukasz, który pozwala przechowywać transformację w formie SQT. Prawdopodobnie możliwe jest uproszczenie obliczeń; ale przynajmniej wymagana przestrzeń dyskowa nie zostanie zwiększona.

sam hocevar
źródło
Dziękuję za wyjaśnienie. BTW, czy znasz jakieś zasoby, w których mógłbym przeczytać więcej na temat sztuczek reprezentacyjnych SQT?
pachanga
Popraw mnie, jeśli się mylę, ale wydaje się, że innym rozwiązaniem byłoby przechowywanie czwartorzędu w normalny sposób, a jeśli musisz uwzględnić tłumaczenie wokół dowolnego punktu / osi, a następnie zbuduj macierz Q z tym dołączonym, po prostu wyodrębnij wektor translacji z tej macierzy (zwykle w ostatniej kolumnie) i dodaj ją do wektora translacji obiektów, a następnie wyrzuć tymczasową macierz.
johnbakers,
15

Wszystkie kanoniczne formuły rotacyjne użyte do wyprowadzenia macierzy rotacji służą do rotacji wokół źródła. Jeśli zamiast tego chcesz zastosować obrót wokół określonego punktu, musisz najpierw przesunąć początek - lub, równoważnie, przesunąć obiekt, aby punkt, który chcesz obrócić, znajdował się u początku.

Najpierw rozważ przypadek 2D, ponieważ jest on prostszy, a technika skalowana. Jeśli miałeś sześcian o szerokości 2 wyśrodkowany na początku i chciałbyś go obrócić o 45 stopni wokół jego środka, byłoby to trywialne zastosowanie macierzy obrotu 2D .

Ale jeśli zamiast tego chcesz go obrócić wokół jego prawego górnego rogu (znajdującego się w 1,1), najpierw musisz go przetłumaczyć, aby ten narożnik był na początku. Można tego dokonać tłumacząc -1,-1. Następnie możesz obrócić obiekt jak poprzednio, ale musisz to zrobić, tłumacząc go wstecz (o 1,1). Ogólnie rzecz biorąc, aby uzyskać macierz obrotu Rdla obrotu rokoło punktu P, należy:

R = translate(-P) * rotate(r) * translate(P)

gdzie translatei rotatesą odpowiednio kanoniczne macierze translacji / rotacji. Tak się składa, że ​​skaluje się w sposób trywialny do 3D, z wyjątkiem konieczności podania osi do obrotu - zawsze możesz wybrać kanoniczne macierze obrotu osi X, Y lub Z, ale byłoby to nudne. Będziesz chciał zastosować dowolną macierz obrotu kąta osi . Twój finał Rw 3D to:

R = translate(-P) * rotate(a,r) * translate(P)

gdzie ajest wektorem jednostek reprezentującym oś obrotu i Pjest teraz punktem 3D w przestrzeni modelu reprezentującym punkt obrotu.

Tak się składa, że ​​czwartorzędy można konwertować na i z reprezentacji macierzowych, dzięki czemu możesz dokonać konkatenacji w ten sposób, jeśli chcesz. Lub możesz po prostu zostawić wszystko jako macierze (czwartorzędy mają pewne fajne zalety, takie jak łatwiejsza interpolacja w rozsądny sposób, ale to, czy potrzebujesz, zależy od ciebie).

Również:

Wizualizuję to jako obracanie się wokół wektora, którego ogon nie jest ustawiony w miejscu pochodzenia.

Ściśle mówiąc, podczas gdy wektory mogą być używane do reprezentowania pozycji poprzez uznanie ich za przemieszczenia od początku, wektor sam nie ma pozycji, więc wizualizacja jednej z nich jest trochę niezwykła.


źródło
Dzięki, to dobra odpowiedź. Nie pasuje to jednak do ograniczeń mojego systemu. Powinienem był zawrzeć w swoim pytaniu: „czy można to zrobić, biorąc pod uwagę te ograniczenia?” I myślę, że odpowiedź brzmi, że tak nie jest, ponieważ wymaga to dwóch tłumaczeń, a ja tylko jednego. Czy jest to nieunikniona wada zastosowania SQT jako reprezentacji przekształceń afinicznych?
notlesh
Idealnie pasuje do twoich ograniczeń. Macierz R (utworzona jako translate-rotate-translate-back) jest macierzą rotacji. Zamień Q na R w systemie „SQT”, aby uzyskać bardziej powszechny paradygmat skalowania-obracania-tłumaczenia i gotowe. To ostatnie tłumaczenie jest niezależne od dwóch tłumaczeń pośrednich wykonanych w celu uzyskania pożądanego obrotu.
Proponujesz zastąpienie czwartorzędu macierzą? To o 12 bajtów więcej na obiekt (8, jeśli przechowuję go jako macierz 4x3)! Ale uciszę we mnie optymistę i dam mu wir. (To faktycznie prawdopodobnie nie będzie nawet równe 2kb wzrostu śladu ...) Dzięki za odpowiedzi.
notlesh
Możesz - możesz także konwertować między nimi, konstruując w ten sposób ćwierć obrotu i podłączając ponownie do istniejącego systemu.
1
@SamHocevar: Alternatywnie, dowolną ich kombinację można wyrazić jako pojedynczą śrubę .
Martin Sojka,