[ glorius @ 03.10.2003. 14:44 ] @
Veciti problem - rotacija.

U OpenGL kao i u svakom drugom 3D sistemu postoje world i object transformacije.
Problem je u tome sto ne mogu da pratim vrednosti uglova posle mesanja eworld i local transformacije.

Evo na sta mislim:
U 3D studio Max-u objekat mozemo rotirati oko local origin-a i oko world origin-a ( i oko drugih, ali me za sada zanimaju samo ova dva koordinatna sistema).

Zelim da simuliram switch-ovanje izmedju ova dva sistema kada rotiram objekat.

Problem je u ovome:

glRotatef( xAngle, 1, 0, 0 ) - oko x
glRotatef( yAngle, 0, 1, 0 ) - oko y
glRotatef( zAngle, 0, 0, 1 ) - oko z

Pri prvoj rotaciji objekat se rotira oko WORLD ose, a pri ostalim oko svojih NOVIH LOKALNIH osa. NOVE jer ih je prva rotacija rotirala u prostoru.

Ako bi bilo ovako:

glRotatef( yAngle, 0, 1, 0 ) - oko y
glRotatef( xAngle, 1, 0, 0 ) - oko x
glRotatef( zAngle, 0, 0, 1 ) - oko z

Ovde se vrsi WORLD rotacija oko y ose a LOCAL rotacije oko x i z.

Meni trebaju vrednosti projekcija osa lokalnog koord. sistema na world koordinatni sistem ( to sus u sustini pravi uglovi objekta ).

Kako uraditi pravu rotaciju u WORLD koord. sistemu oko sve tri ose?

Mogu da uradim samo jednu rotaciju oko X, pa tek u sledecem ciklusu programa oko Y da bi to bila WORLD transformacija, ali to je neupotrebljivo.

Pokusao sam i preko EULER-ovih jednacina da prebacim iz lokalnog u world sistem, ( koriscenjem sfernih koordinata ) ali, problem je sto je prva rotacija uvek oko WORLD ose a ne oko lokalne.

Znaci: rotiranje oko lokalnih osa - dobiti projekcije na world.

i

rotiranje oko world osa - dobiti tacne projekcije na world koord. sistem.
[ Mrav @ 04.10.2003. 12:10 ] @
Jesi li pogledao glpushMatrix() i glpopMatrix() , takodje je bolje imati negde parametar rotacije i svaki put polaziti od pocetnog stanja i ponovo rotirati (ne glrotate(ugao), pa glrotate(ugao koji se dodaje rotaciji) nego glPushMatrix pa glRotate(ugao) pa glPopMatrix() pa glRotate(osnovni ugao + ugao za koji se povecava/smanjuje rotacija) ovo se radi zbog nepreciznosti racunanja rotacije, sto dovodi do toga da kada vezujes jednu na drugu rotaciju sa velikim brojem rotacija, ne dobijes zeljeni rezultat (neka osa moze lako da "pobegne").

Znaci resenje za ovo prvo izgleda otprilike ovako:

Rotiras oko world sistema
glRotate(x,y,z)
glPushMatrix(GL_MODELVIEW)
glTranslate(na poziciju objekta sto postavlja novi centar rotacije)
glRotate(rotacija objekta oko svog centra rotacije)
IscrtajObjekat()
glPushMatrix() // ovo te vraca na world matricu
Ako sada opet zelis da rotiras u world sistemu (matrici), mozes da ponovis ceo postupak, ali da ne bi imao problem sa ulancavanjem rotacija (rotiras oko jedne ose, pa kad rotiras oko druge ne dobijes rotaciju oko zeljene ose jer je prva rotacija promenila matricu, uradi:
glLoadIdentity() //ucitas identity matricu tj pocetnu matricu gde je iz tvog ugla gledano x=x y=y z=z osa.
glRotate(x+za koliko zelis da povecas ugao, y+… itd.)
i onda ponovis ono sto sam gore naveo (znaci od glPushMatrix pa nadalje), s tim da naravno da negde treba da drzis uglove u promenljivama i da ih onda povecavas/smanjujes jer ponovo rotiras za ukupni ugao a ne dodajes ugao na ugao :)
i pazi, mozes bez problema da rotiras oko svih zeljenih osa u jednom glRotate pozivu da se ne bi pogubio oko toga oko koje sada ose treba da rotiras da bi dobio zeljeni efekat, inace cuvanjem matrice sa glPushMatrix i vracanje sa glPopMatrix se recimo lepo koristi kada zelis da napravis zglobove:
iscrtas Parent
glpush
iscrtas child
glpush
iscrtas sledeci child
glpop
glpop
s tim da dodajes rotaciju za svaki child u odnosu na njegovog roditelja posle glpush
i time dobijas hijerarhiju rotacije/translacije u odnosu roditelj - dete.

Nadam se da se nisam i ja pogubio u brzini, ali mislim da ces iz ovoga moci da izvuces ono sto ti treba.

[ glorius @ 05.10.2003. 23:37 ] @
Hvala na odgovoru!

Ali...

Mozda delujem skepticno, ali glPushmatrix(GL_MODELVIEW) ne menja iz WORLD-a u MODEL view, jer f-ja ne uzima parametre.

Ali, pored PROJECTION, VIEW i MODELVIEW matrice, gde je WORLD matrica ??

Kako TACNO odvojiti transformacije oko WORLD koordinatnih osa ( one su uvek:

x (1, 0, 0)
y (0, 1, 0)
z (0, 0, 1)

)

od lokalnih osa objekta. ( ili ja sve ovo pogresno shvatam !? )

Mozda gusim, ali odgovor nije odgonenuo misteriju.

[ Mrav @ 06.10.2003. 11:49 ] @
Evo razjašnjenja.
Ne postoje model, view i world matrice u Opengl-u, postoji jedna matrica modelview (zato i postoji parametar GL_MODELVIEW koji ukazuje na tu matricu) ona moze biti (ali ne mora) matrica kojom predstavljas world koordinatni sistem.
Znači, imas jednu modelview matricu koja ti predstavlja world. Ako je ne menjaš i crtaš objekte, oni se pojavljuju onako kako su zadati (jer po defaultu modelview matrica predstavlja identity matricu gde je x=x y=y i z=z i gde nema rotacije), ako je menjaš, isto to samo što svaka tačka koju iscrtavaš biva pomnožene kroz tu novu matricu (koja više nije identity, jer može biti rotirana, skalirana, pomerena) i tako se dolazi do njenog novog položaja. Bukvalno, ne pomeraš, rotiraš, skaliraš nikada objekte onako kako si ih zadao, već matricu u kojoj se oni nalaze.
Predpostavljam da dobro znaš kakva je struktura stack (first in last out, FILO), kada pozoveš glPushMatrix(GL_MODELVIEW), trenutnu modelview matricu (ona koja ti predstavlja world) stavljaš na stack i manipulišeš novom matricom (koja je u startu identity), ako sada uradiš recimo traslate, pomeraš koordinatni početak tog koordinatnog sistema u odnosu na prethodni koji je na stacku (world), sada sve što nacrtaš biće pomereno u odnosu na world (znači svi sledeći objekti su pomnoženi sa world pa sa tom sledećom, nazovimo je local matricom) time dobijaš apstrakciju jednog lokalnog koordinatnog sistema za sve sledeće objekte koje crtaš.
Sada kad rotiraš recimo tu matricu, rotiraš objekte koje crtaš u njoj u odnosu na tu lokalnu matricu a ne u odnosu na world.

To je ono što se tiče MODELVIEW matrice, imaš i PROJECTION matricu koja definiše perspektivu objekata (sve tačke se računaju kroz MODELVIEW matricu, pa onda kroz PROJECTION matricu) i to je to.

U prilog ovome evo malo pseudokoda kojim ću pokušati da predstavim rešenje za ono što si u stvari tražio (prebacivanje rotacije sa local na world).

struct rotacija {
int x;
int y;
int z;
} // čuva rotaciju za bilo koji koord sistem

void rotiraj_sistem(rotacija &rot, int x=0, int y=0, int z=0)
{
rot.x += x;
rot.y += y;
rot.z += z;
// ne pisem proveru, ali ako je ugao recimo 288 a dodaš 100 izlazni ugao treba da je 28 a ne 388 i obrnuto u minusu
}


bool sistem = true; true ako rotiramo world, false ako rotiramo object

rotacija world;
rotacija object;

int oldmouse_x=0, odlmouse_y=0;

mouse(int x, int y)
{
if (sistem == true) //rotiramo world
podesavas rotaciju , ako miš ide desno recimo povećavaš rotaciju po y itd.
primer: ako odlmouse_x < x onda world.x += 1;
if (sistem == false) // rotiramo object
object.x +=1;
oldmouse_x = x;
oldmouse_y = y;
}


drawobject()
{
crtas objekte;
}

draw()
{

glLoadIdentity() // potrebno da ne bi množio ponovo sa matricom iz prethodne petlje
glRotate(world.x, world.y, world.z);
glPushMatrix(GL_MODELVIEW);
glRotate(object.x, object.y, object.z);
drawobject();
glPushMatrix();
}


[ glorius @ 08.10.2003. 00:31 ] @
glPushMatrix(GL_MODELVIEW). Ova f-ja ne uzima parametre. Mozda mislis na glMatrixMode(GL_MODELVIEW)? ... Hvala!
[ Mrav @ 08.10.2003. 09:15 ] @
U pravu si za void glPushMatrix(void), prošlo je neko vreme od kada sam poslednji put kodirao OpenGL (nema se vremena).
Po odgovoru izgleda mi da sam ti pomogao da "graspuješ" koncepte :)
[ yooyo @ 19.10.2003. 00:09 ] @
Uhhh... nalateo si na "gimbal lock". Da bi se ovo izbeglo korise se quaternioni.
Potrazi malo po net-u neku matematicku biblioteku koja zna da radi sa
quaternionima.

yooyo
[ Reljam @ 19.10.2003. 09:41 ] @
Mislim da nema potrebe potezati quaternione za ovo. yooyo jeste u pravu, problem je u gimbal locku, ali bas zato se koriste matrice za rotaciju a ne eulorovi uglovi, jer oni ne rade bas najbolje u 3D.

Dakle, glorius, nemoj uopste da pokusavas da pretvaras matrice u uglove, vec radi samo sa matricama.

Znaci ako hoces da rotiras objekat oko njegove X ose za 0.1 radian, samo pomnozi world matricu objekta sa odgovarajucom matricom:

D3DXMATRIX World;
D3DXMATRIX Rot;

D3DXMatrixRotationX( &Rot, 0.1f );
D3DXMatrixMultiply(&World, &World, &Rot);

Ovo je ocigledno primer iz D3Da, zaboravio sam kako se ovo radi u OpenGLu, ali siguran sam da postoje ekvivalentne funkcije.