OpenGl rotacje w lokalnym układzie współrzędnych

0

Piszę grę w kotka i myszkę w C++ z OpenGlem, chciałabym żeby obracały się one wokół własnej osi, jednak cały czas obracają się wokół środka globalnego układu współrzędnych (zamiast lokalnych). Taki jest kod (tzn. kluczowa część kodu):

    void renderRoom()
    {
       glPushMatrix();
       glMatrixMode(GL_MODELVIEW);
       glLoadIdentity();
       glTranslatef( 0, 0, - 4.0 );
     
       glBegin(GL_QUADS);
       ...
       glEnd();
       glPopMatrix();
    }
     
     
    void renderMouse()
    {
      glPushMatrix();
       glTranslatef(mmovex, mmovey, 0.0);
       glRotatef(mangle, 0.0, 0.0, 1.0);
     
       glBegin(GL_POLYGON);
       glColor3f(0.0, 0.0, 0.0);
       glVertex3f(mousepoz[0][0], mousepoz[0][1], mousepoz[0][2]);
       glVertex3f(mousepoz[1][0], mousepoz[1][1], mousepoz[1][2]);
       glVertex3f(mousepoz[2][0], mousepoz[2][1], mousepoz[2][2]);
       glVertex3f(mousepoz[3][0], mousepoz[3][1], mousepoz[3][2]);
       glEnd();
       glPopMatrix();
    }                   
   
    void Display()
    {
       KeyOperations();
       SpecialKeyOperations();
     
       renderRoom();
       renderMouse();
       renderCat();
       glFlush();
       glutSwapBuffers();
    } 

Funkcja renderCat wygląda analogicznie jak rendeMouse, w tablicy mousepoz są zapisane pozycje "wierzchołków" mysz (na razie jest to kwadrat). mmovex, mmovey, mangle są inicjowane zerami i zmieniają się w razie wciśnięcia odpowiednich klawiszy. Macie może pomysł czemu tak się dzieje? Z góry dzięki za pomoc.

0

Przejście z lokalnego na globalny układ współrzędnych i odwrotnie to zamiana kolejności transformacji.

Daj najpierw Rotate a potem Translate.

0

Właśnie taka zamiana nic nie pomaga. :/

0

Właśnie taka zamiana nic nie pomaga
Musi. Chyba że masz coś nie tak z układem współrzędnych. To wygląda podejrzanie:

       glMatrixMode(GL_MODELVIEW);
       glLoadIdentity();
       glTranslatef( 0, 0, - 4.0 );

to powinno być raczej w jakimś "init" a nie w pętli przy każdym rysowaniu...

Pokaż jak inicjujesz GL_MODELVIEW i GL_PROJECTION.

0

Przed glPushMatrix spróbuj dać glRotatef

0
Azarien napisał(a):

Daj najpierw Rotate a potem Translate.

W OpenGLu jest post multiply, czyli macierz przekształcenia jest mnożona przez nową macierz definiowaną przez powyższe instrukcje. Dlatego wywołanie glRotate, a potem glTranslate wykona najpierw translacje a potem rotacje. Czyli błąd leży gdzie indziej, może w pozycjach wierzchołków?

0

Faktycznie, nie w tym błąd, ale zdanie "wykona najpierw translacje a potem rotacje" nic nie znaczy bez podania jaki układ współrzędnych masz na myśli.
Lepiej to rozumieć tak: transformacje wykonywane są w podanej kolejności w aktualnym, zmienionym przez poprzednie instrukcje układzie współrzędnych (żaden globalny tak naprawdę nie istnieje). Jest to jednak tożsame ze stwierdzeniem: transformacje wykonywane są w stałym, globalnym układzie współrzędnych w kolejności odwrotnej niż podano w kodzie.

Dlatego jest różnica między Rotate->Translate a Translate->Rotate, co w rachunku macierzowym jest konsekwencją tego, że mnożenie macierzy nie jest przemienne.

Ponieważ jednak nie kolejność operacji jest problemem w tym przypadku, stawiam że to coś ze stosem (albo stanem).
Jeżeli macierz modelu jest ustawiana wewnątrz pushmatrix/popmatrix (i można mieć obawę że tylko tam), to jaka macierz jest na stosie po tym glPopMatrix?

W OpenGL-u niestety jedna zagubiona albo niesparowana instrukcja może wszystko zepsuć.

1

Tak, miałem na myśli globalny układ współrzędnych. Wracając do problemu. Nawet jakby w macierzy MV, czy projekcji były jakieś śmieci to prędzej nic by nie było widać na ekranie. Prawdopodobnie współrzędne tego kwadratu masz w jednej ćwiartce układu współrzędnych. I pokaż jak wygląda inicjalizacja tych macierzy, powinno być coś podobnego do tego:

glViewport(0, 0, winSize.width, winSize.height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, (GLfloat)winSize.width/winSize.height, 0.5f, 1500.0f);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt( 0, 0, -1,    0, 0, 0,   0.0f, 1.0f, 0.0f);
Azarien napisał(a):

W OpenGL-u niestety jedna zagubiona albo niesparowana instrukcja może wszystko zepsuć.

Tak jak ze wszystkim innym ;) Jak się nie wie co się robi to jest ciężko, dlatego podejście "zróbmy to na shaderach" jest lepsze bo trzeba wiedzieć co się robi, żeby cokolwiek wyświetlić.

0

To tą inicjalizację macierzy mam napisać na początku Display? (dopiero się uczę opengl, więc jeszcze niezbyt ogarniam to wszystko)

0

Nie. Na poczatku programu, po utworzeniu okna ale przed pierwszym Display.

0

Ok, przed wywołaniem Display() zapisałam : glViewport(0, 0, 1000, 700);glMatrixMode(GL_MODELVIEW);glLoadIdentity();(Nie napisałam reszty bo mam scenę w 2d z widokiem z góry i chcę widzieć całą scenę), usunęłam glMatrixmode i glLoadIdentity z renderRoom.. Teraz nie wyświetlają mi się żadne elementy sceny. oO

0

Pokaż cały kod.

0

tutaj wkleiłam prawie cały kod (nie wkleję całego bo to kilkanaście plików): http://ideone.com/DcwGbk

0
#ifdef WIN32
        glutAddMenuEntry( "Wyjście", EXIT );
#else
        glutAddMenuEntry( "Wyjscie", EXIT );
#endif

hmm.. po co te ifdefy?

        //inicjalizacja macierzy
    glViewport(0, 0, 1000, 700);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

wywal

void Reshape(int width, int height)
{
        //...
}

tutaj umieść:

    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
       glLoadIdentity();
       gluPerspective(...);
    glMatrixMode(GL_MODELVIEW);
       glLoadIdentity();
       gluLookAt(...);

a co powinno być w gluPerspective i gluLookAt?

to już zależy, ja robię tak:

			gluPerspective(60, (GLdouble)width/height, 1, 100);
			gluLookAt(0,0,20, 0,0,0, 0,1,0);

ale z wartościami trzeba poeksperymentować.

0

ifdefy po to żeby były napisy z lub bez polskich znaków, tak czytałam. To inicjalizację macierzy mam dać do funkcji Reshape? Przecież ona odpowiada za zmienianie rozmiaru okna. I czemu mam używać macierzy PROJECTION, gluPerpective i gluLookAt, skoro mam elementy sceny w 2D i chcę mieć widok na całą scenę?

0

W każdym razie teraz z tą inicjalizacją scena wygląda tak: http://oi50.tinypic.com/169gw2h.jpg, a rotacje wykonują się tak samo jak przedtem.

0

To inicjalizację macierzy mam dać do funkcji Reshape?
Tak, zdecydowanie.

skoro mam elementy sceny w 2D i chcę mieć widok na całą scenę?
To użyj gluOrtho2D zamiast gluPerspective, ale gluLookAt powinno być.

0

ok, rozumiem, ale nie pomogło to na rotacje ;/

0

W końcu napisałam własne funkcje obliczające pozycje wierzchołków, więc temat jest do zamknięcia.

1 użytkowników online, w tym zalogowanych: 0, gości: 1