Czy nie byłoby wspaniale gdybyśmy mogli obracać swobodnie nasz model za pomocą myszy? Właśnie na tym polega rotacja sferyczna. W tym tutorialu przedstawię moją implementację tej techniki i powody, dla którego warto wykorzystać ją w Twoich projektach.
Moja implementacja klasy ArcBall jest oparta na implementacji Brettona Wadea, która z kolei opiera się na zamieszczonej w "Graphic Gems" autorstwa Kena Shoemake'a. Poprawiłem jednak kilka błędów i nieco zoptymalizowałem kod.
Rotacja sferyczna działa dzięki mapowaniu współrzędnych kliknięcia w okno bezpośrednio w koordynaty wirtualnej kuli, tak jakby znajdowała się ona tuż przed Tobą.
Aby osiągnąć taki efekt, musimy najpierw przeskalować koordynaty myszy z zakresu [0...szerokość), [0...wysokość) do [-1...1], [1...-1] - (zapamiętaj, że odwracamy zwrot osi Y, więc osiągniemy poprawne koordynaty OpenGL). Wygląda to tak:
Jedynym powodem, dla którego przeskalowujemy współrzędne do zakresu [-1...1] jest fakt, że ułatwi nam to obliczenia matematyczne. Szczęśliwym zbiegiem okoliczności pomoże to również komputerowi w optymalizacjach.
Następnie obliczamy długość wektora i ustalamy czy jest wewnątrz, czy na zewnątrz sfery. Jeśli jest wewnątrz, zwracamy wektor z wewnątrz sfery, w przeciwnym wypadku normalizujemy punkt i zwracamy najbliższy zewnętrzu sfery punkt.
Kiedy już mamy oba wektory, możemy obliczyć wektor prostopadły do wektora początkowego i końcowego, które tworzą kąt będący kwaternionem. Te informacje nam wystarczą do stworzenia macierzy.
System rotacji sferycznej jest inicjowany przy pomocy następującego konstruktora. NewWidth i NewHeight to szerokość i wysokość okna.
Kiedy użytkownik kliknie myszką wewnątrz okna, obliczany jest początkowy wektor w zależności od tego, w którym miejscu nastąpiło kliknięcie.
Kiedy użytkownik przeciąga kursor myszy, wektor końcowy jest modyfikowany przez funkcję draw() i jeśli podaliśmy jako parametr kwaternion, to jest on uzupełniany zgodnie z wynikiem rotacji.
Jeśli zmieniają się wymiary okna, uaktualniamy system rotacji sferycznej za pomocą funkcji:
Zmienne potrzebne do użycia systemu rotacji sferycznej we własnym projekcie:
Transform to nasza ostateczna transformacja - nasz obrót i wszelkie ewentualne translacje, jakie możesz chcieć dokonać. LastRot to ostatni obrót, jaki otrzymaliśmy pod koniec przeciągania. ThisRot to obrót podczas przeciągania. Wszystkie inicjalizujemy jako macierze tożsamościowe.
Kiedy klikamy w oknie, mamy tożsamościową macierz obrotu. Kiedy przeciągamy kursor, obliczamy obrót od początkowego punktu kliknięcia do aktualnych współrzędnych myszy. Pomimo, że używamy tych informacji, aby obrócić obiekt na ekranie, ważne jest że nie obracamy naszej wirtualnej kuli.
Teraz zaczynamy używać LastRot i ThisRot. LastRot to wynik wszystkich obrotów aż do teraz, podczas gdy ThisRot to aktualny obrót. Za każdym razem, gdy zaczynamy przeciągać kursor, ThisRot jest modyfikowane przez oryginalny obrót, a potem przez LastRot. Kiedy kończymy przeciąganie myszą, LastRot zostaje przypisana wartość ThisRot.
Gdybyśmy sami nie dodawali wyników obrotów, model zaczynałby obrót od wyjściowej pozycji po każdym kliknięciu. Na przykład: jeśli obrócimy model wokół osi X o 90 stopni, a potem o 45 stopni, chcielibyśmy otrzymać obrót o 135 stopni, a nie o ostatnie 45.
Jeśli chodzi o pozostałe zmienne (oprócz isDragged), wszystko co musisz zrobić, to uaktualniać je w odpowiednim czasie zależnie od twojego systemu. Rotacja sferyczna wymaga podania jej nowych wymiarów okna za każdym razem, kiedy jego rozmiar się zmienia. MousePt jest uaktualniane gdy tylko poruszymy myszą lub gdy przycisk myszy jest wciśnięty. isClicked / isRClicked jest modyfikowane po naciśnięciu przycisku myszy. isClicked jest używane do ustalania kliknięć i przeciągnięć. Użyjemy isRClicked do resetowania wszelkich obrotów (zamiany macierzy na tożsamościową).
Dodatkowy kod aktualizacji w/w zmiennych wyglądałby pod NeHeGL/Windowsem mniej-więcej tak:
Kiedy już mamy gotowy kod aktualizacji zmiennych, nadszedł czas umieścić na miejscu logikę kliknięcia. Poniższy kod jest bardzo łatwy do zrozumienia, jeśli wiesz wszystko, co było powiedziane powyżej.
Ten kod zajmuje się wszystkim za nas. Teraz musimy już tylko ustawić naszą nową macierz transformacji. A to naprawdę proste:
Dołączyłem przykład, który ilustruje wszystko powyższe. Nie musisz używać mojej matematyki czy funkcji, prawdę mówiąc polecam przystosować to do Twojego własnego systemu matematycznego, jeśli czujesz się wystarczająco pewnie. Jednak nie jest to konieczne, aby system działał.
Teraz, kiedy już wiesz, jakie to proste, nie powinieneś mieć problemów z dodaniem rotacji sferycznej do swoich projektów.
przykładowy kod znajduje się na dole strony