2013-02-16 12 views
6

Tworzę grę, która wykorzystuje całą planetę do swojej mapy. Tesselowałem sferyczną planetę using this technique i teraz dodałem elementy sterujące aparatu.Obracanie kamery do punktu

Sfera ma wymiary 1 do -1, więc każdy punkt na kuli jest również znormalizowanym wektorem. W tym samym czasie jedna z sześciokątnych płytek, które tworzą kulę, jest "wybraną" płytką. Gracz może następnie przenieść zaznaczenie do sąsiednich płytek za pomocą D-pada. Mogą również samodzielnie obracać kamerę za pomocą analogowego drążka analogowego. Muszę wykonać dwie czynności w odniesieniu do wybranej płytki i kamery. Po pierwsze, muszę mieć możliwość przełączenia wyboru na kafelek znajdujący się najbliżej aparatu. Po drugie, muszę wyśrodkować kamerę na podświetlonym kafelku. Kula znajduje się na początku, a kamera znajduje się w punkcie (0,0,1). Silnik graficzny pozwala mi tylko obrócić kamerę wokół osi X i Y, więc aby rozwiązać pierwszy problem, używam kwaternionów do obracania punktu (0,0,1) wokół osi x, a następnie y, aby znaleźć punkt w 3D przestrzeń, w której aparat jest:

private Quaternion quat = new Quaternion(0,0,0,0); 
    private double[] output = new double[4]; 
    private double[] cam = new double[3]; 

    private double camX = 0; 
    private double camY = 0; 
    private double camZ = 1; 


    private double[] getCamPosition(){ 

     quat.setAxisAngle(1, 0, 0, Math.toRadians(-graphicsEngine.getRotationX())); 
     quat.RotateVector(camX, camY, camZ, output);    
     cam[0] = output[0]; 
     cam[1] = output[1]; 
     cam[2] = output[2]; 

     quat.setAxisAngle(0, 1, 0, Math.toRadians(-graphicsEngine.getRotationY())); 
     quat.RotateVector(cam[0], cam[1], cam[2], output);   
     cam[0] = output[0]; 
     cam[1] = output[1]; 
     cam[2] = output[2]; 

     return cam; 
    } 

i następnie porównać ich odległości od środka masy każdej płytki i położenia kamery i wziąć płytkę, która jest najbliżej będzie nowo wybrany dachówka.

Jednak, aby rozwiązać drugi problem, chcę zrobić odwrotność. Chcę wziąć środek ciężkości (który już jest w postaci znormalizowanego wektora) i dowiedzieć się, jaki jest obrót wokół osi X, a obrót wokół osi Y jest potrzebny, aby kamera znalazła się na środku.

W tej chwili "obróciłem kamerę z powrotem do punktu (0,0,1), a następnie uzyskałem kąt w osi X i osi Y między (0,0,1) i środkiem ciężkości i używając go do ponownego obrócenia kamery:

private double[] outputArray = new double[2]; 

/** 
* Cam is always (0,0,1) 
*/ 
public void centreOnSelected(double camX, double camY, double camZ){   

    selectedTile.getCentroidAngles(outputArray); 

    outputArray[0] -= Math.atan2(camZ, camY); 
    outputArray[1] -= Math.atan2(camX, camZ); 

    // this determines if the centroid is pointing away from the camera 
    // I.e. is on the far side of the sphere to the camera point (0,0,1) 
    if(!selected.getCentroidDirectionY(camX, camZ)){ 
     outputArray[0] = -Math.PI - outputArray[0];   
    } 

    graphicsEngine.rotateCam(Math.toDegrees(outputArray[0]), Math.toDegrees(outputArray[1])); 


} 

aw selected (klasy dachówka)

void getCentroidAngles(double[] outputArray){ 
    outputArray[0] = Math.atan2(centroidZ, centroidY); 
    outputArray[1] = Math.atan2(centroidX, centroidZ); 

} 

problemem jest to nie działa, (oś X zawsze wydaje się być wyłączona) i jestem prawie pewien, że ma to związek z matematyką uzyskiwania kątów i robienia obrotowego. Uwaga: silnik graficzny obraca się najpierw wokół oś X, następnie wokół Y:

 gl.glRotatef(mRotateX, 1, 0, 0); 
     gl.glRotatef(mRotateY, 0, 1, 0); 

w centroidy są w odpowiednim miejscu, a aparat zdecydowanie obraca ją w odpowiednich ilościach, więc jestem pewien, że problem nie jest z silnikiem graficznym. Nie jest również ponowne ustawienie aparatu z powrotem do (0,0,1) jako Sprawdziłem to działa poprzez intensyfikację ramach programu

Mam również film do zilustrowania problemu:

http://www.youtube.com/watch?v=Uvka7ifZMlE

Przez wiele dni było to przyczyną problemów, więc jakakolwiek pomoc w uzyskaniu tego byłoby bardzo cenne!

Thanks James

Odpowiedz

2

Niestety nie w pełni zrozumieć, co tu się dzieje, i nie może zaoferować kompleksowe rozwiązanie, ale może przynajmniej zwrócić uwagę na pewne problemy patrzeć.

Nigdy nie używałem glRotatef, ale jestem trochę zdezorientowany co do kolejności i znaku transformacji tutaj - na przykład, czy naprawdę robisz rotację x najpierw biorąc pod uwagę kolejność połączeń glRotatef?

W każdym razie, przynajmniej część problemu tutaj pochodzi z tych równań

outputArray[0] = Math.atan2(centroidZ, centroidY); 
outputArray[1] = Math.atan2(centroidX, centroidZ); 

Po pierwsze, pan miał na myśli (centroidY, centroidZ) w pierwszym? Bardziej poważnie, kąty, które tu uzyskasz, nie mogą być użyte do zbudowania obrotu przenoszącego na twoim centroidzie lub odwrotnie. Załóżmy na przykład, że chcesz obrócić swój wektor centroidowy do (0,0,1). Każde z twoich 2 obrotów może być użyte do obracania się wokół pojedynczego ustawienia osi jednego komponentu do zera. Na przykład, obrót o outputArray[0] wokół osi x odpowiednim znakiem by ustawić składnika Y zero (zakładając, że argumenty atan2 zostały zamienione). Alternatywnie obrót przez outputArray[1] prawej znak wokół osi y mógł ustawić składową x 0. Ale po wykonaniu x obrót pierwszy (powiedzmy), aby ustawić składowych Y na 0 środka ciężkości zmian Vector - teraz obrót wokół osi y to ustawienie x komponentu na 0 nie jest już opisane przez outputArray[1].

Odpowiednie formuły tych rzeczy zawsze mają atan2 dla jednego kąta oraz acos lub asin dla innych. Na przykład, jeśli chcesz kąty dla aktywnego obrotu, które niosą wektor (1,0,0) na (x,y,z) byłoby użyć

first_angle_around_x = -asin(y) 
second_angle_around_y = atan2(x, z) 

Aby wykonać (x,y,z) na (1,0,0) byłoby użyć

first_angle_around_x = atan2(y, z) 
second_angle_around_y = -asin(x) 

(kąty te opisują obroty wokół osie x, y, które są przeciwne do ruchu wskazówek zegara, gdy oś "szturcha cię w oczy".)

Kolejny problem jest tutaj

outputArray[0] -= Math.atan2(camZ, camY); 
outputArray[1] -= Math.atan2(camX, camZ); 

Odejmowanie takich kątów działa tylko w przypadku obrotu wokół pojedynczej osi. Kiedy budujesz transformacje złożone z rotacji wokół różnych osi, relacja staje się znacznie bardziej skomplikowana - dlatego przydatne stają się macierze i kwaterunki. Domyślam się, że ten kod może nie mieć znaczenia, jeśli wejścia camX-Z są zbędne, jak sugeruje komentarz poprzedzający metodę (chociaż w tej chwili posiadanie składników Z i Y, tak jak tu są, daje wynik niezerowy, który może być rekompensując im, że są "złym" sposobem w pierwszych równaniach, o których wspomniałem, nie jestem pewien, czy jest to celowe).

Jest też podstawowym problemem przy okazji jesteś ruchomego aparatu do wybranej płytki, choć to trochę prywatną czy to rzeczywiście problem. Ponieważ obracasz tylko wokół osi X i Y, masz unikalną orientację kamery dla każdego punktu na twojej planecie. Problem polega na tym, że nie ma możliwości ciągłego wybierania takiej orientacji - aby zobaczyć, jak to wyobraża się pole wektorowe na planecie, gdzie wektor w każdym punkcie jest wektorem jednostkowym, wskazującym wzdłuż kierunku ekranu x, gdy kamera znajduje się powyżej tego punktu. To pole nie może być ciągłe przez Hairy Ball Theorem. W praktyce oznacza to, że na planecie będzie jakiś punkt, w którym zrobienie czegoś, co wydaje się małą regulacją położenia kamery, spowoduje obrót planety o 180 stopni na ekranie. Jeśli chcesz tego uniknąć, możesz wybrać orientację zamiast aktualnej pozycji kamery, aby zminimalizować rotację.Oznacza to na przykład, że planeta może się "wywrócić" na ekranie, jeśli kamera porusza się w zamkniętej pętli, co może nie być pożądane w grze. Wymaga także, aby twój silnik mógł wykonywać obroty na wszystkich 3 osiach.

+0

Interesujące, dzięki! Rozumiem z krążeniem wokół, ale nigdy nie zdawałem sobie sprawy, że ma imię (znacznie mniej, tak zabawne jak twierdzenie Hairy Ball). Takie zachowanie podczas jazdy na kółkach nie jest niczym niezwykłym w grach komputerowych, w które grałem, i prawdopodobnie będzie tylko pomniejszać graficzną irytację podczas grania w moją grę. Wygląda jednak na to, że na razie będę musiał wyśrodkować/obrócić kamerę na środek ciężkości –