[lnkForumImage]
Download FREE Software.

Confronta i prezzi di migliaia di prodotti.
News Forum Italiano
 Home | Login | Registrati | Ricerca 


 

Forums >

it.comp.giochi.sviluppo

Consigli su l'uso dei quaternioni

marycarl

07/01/2010 16:55:36

Salve a tutti. Chiedo scusa anticipatamente se ho sbagliato sezione (non
conosco bene il sito). Vorrei chiedervi un aiuto su come usare i
quaternioni per creare rotazioni senza gimbal lock (uso XNA con linguaggio
C#). Grazie.

--

questo articolo e` stato inviato via web dal servizio gratuito
http://www.newsla... segnala gli abusi ad abuse@newsland.it


20 Risposte

(Matteo Perenzoni)

08/01/2010 08:29:11

0

On Jan 7, 5:55 pm, maryc...@alice.it (Toty_) wrote:
> Salve a tutti. Chiedo scusa anticipatamente se ho sbagliato sezione (non
> conosco bene il sito). Vorrei chiedervi un aiuto su come usare i
> quaternioni per creare rotazioni senza gimbal lock (uso XNA con linguaggio
> C#). Grazie.

Ciao!
Innanzitutto questo non e' un sito, ma la vecchia e buona "usenet" :)
Ma fa lo stesso: hai postato nel posto giusto!
Io ho da tempo immemore una libreria per i quaternioni che fa un po'
tutto, in c++: se ti fai il porting da solo, posso prestartela. Deve
essere abbastanza corretta perche' la ho usata e strausata. In ogni
caso non e' altro che la riscrittura di una delle tante che si trovano
googlando.
Comunque se devo essere sincero, anche lavorando con le sole matrici
non mi sono mai trovato ad affrontare il problema del gimbal lock (e
qui sono disposto a ricevere anche smentite!): io di solito uso un
sistema di riferimento caratterizzato dalla sua posizione e dai tre
assi nello spazio, e ruoto questi assi per poi ricavare la matrice di
trasformazione dallo spazio globale a quello "locale".
Buona giornata!
________________________
Matteo
http://fuzzware.alte...
"A man with a new idea is a crank until the idea succeds" - M. Twain

Gianpaolo Ingegneri

12/01/2010 13:09:51

0


> Comunque se devo essere sincero, anche lavorando con le sole matrici
> non mi sono mai trovato ad affrontare il problema del gimbal lock (e
> qui sono disposto a ricevere anche smentite!): io di solito uso un
> sistema di riferimento caratterizzato dalla sua posizione e dai tre
> assi nello spazio, e ruoto questi assi per poi ricavare la matrice di
> trasformazione dallo spazio globale a quello "locale".

Alla fine quando si ha piena coscienza di ciò che si realizza, come nel tuo
caso, è difficile incontrare problemi, cioè che un programma non si comporti
come vorresti. Anch'io ho usato in passato matrici e quaternioni per gestire
animazioni anche complesse senza alcun problema.

Ritornando alla domanda di Toty, ricorda che esistono diversi modelli per
rappresentare un oggetto 3d ruotato nello spazio, tra cui la terna di assi
(yaw, pitch, roll), i quaternioni oppure semplicemente una matrice. Se
dovessi usare il criterio della terna di assi o della matrice, per eseguire
una rotazione animata che viene fatta tramite l'interpolazione tra una
chiave di rotazione di partenza ed una di destinazione, in funzione di t,
devi necessariamente convertire tali chiavi in quaternioni, eseguire la
slerp tra i due quaternioni per poi ritornare al tuo precedente modello di
rappresentazione.

L'unico problema potrebbe sussistere quando ci sono angoli maggiori di 180°,
in quel caso la slerp "sceglierebbe" il cammino più breve, ma si può
risolvere benissimo dividendo l'animazione e aggiungendo delle chiavi
intermedie. Se un personaggio deve ruotare da 30 a 330 gradi, con la slerp
lo farà nel senso opposto andando da 30 a -30 gradi, ma se avrai 3 step
30°-180°-330° allora il verso sarà quello che vuoi tu. Quindi un buon modo
per risolvere secondo me è quello di introdurre una eventuale suddivisione
del movimento, anche perchè devi memorizzare in qualche modo l'informazione
sul senso della rotazione, che in questo caso non esiste. Oppure potresti
dire al tuo engine "fammi n giri in senso antiorario" durante la fase di
registrazione delle chiavi, dipende sempre da quello che devi fare. Per
esempio, potresti fare una tua slerp dove dai per esempio questi due angoli
tipo 30° e 1780°, e la slerp si occuperebbe di eseguire nell'intervallo di
rotazione che va da 0 a 1 tutti i giri intermedi che stanno tra 30 e 1780
suddividendo sempre in modo da non superare i 180 gradi per interpolazione.
Così avresti risolto il gimbal ed introdotto una funzionalità interessante,
ci vuole un pochettino di programmazione e di inventiva ;-)

Gianpaolo Ingegneri


Gianpaolo Ingegneri

12/01/2010 13:47:44

0


> e la slerp si occuperebbe di eseguire nell'intervallo di
> rotazione che va da 0 a 1 tutti i giri intermedi che stanno tra 30 e 1780
> suddividendo sempre in modo da non superare i 180 gradi per
> interpolazione.

mi sono accorto che potrebbe essere frainteso, ma intendevo nell'intervallo
di t che va da 0 a 1


marycarl

13/01/2010 19:45:42

0

Gianpaolo Ingegneri ha scritto:

> > e la slerp si occuperebbe di eseguire nell'intervallo di
> > rotazione che va da 0 a 1 tutti i giri intermedi che stanno tra 30 e 1780
> > suddividendo sempre in modo da non superare i 180 gradi per
> > interpolazione.

> mi sono accorto che potrebbe essere frainteso, ma intendevo nell'intervallo
> di t che va da 0 a 1

Non sto progettando nulla di complicato. Ho appena cominciato con i
quaternioni in quanto sono incappato nel gimbal lock in un semplice
programma in cui dovevo ruotare un cubo (attorno all'asse x oppure attorno
all'asse y, in base al tasto digitato).
Il problema è che, ad ogni fotogramma, i punti del cubo tornano alle
coordinate iniziali (in XNA è così) e quindi devo ripetere tutte le
rotazioni avvenute durante il gioco. Avevo provato moltiplicando un
quaternione temporaneo per il quaternione globale (che contiene tutte le
rotazioni avvenute), non c'è più il gimbal lock ma non ruota perfettamente
e comunque ottengo lo stesso effetto ottenuto usando le semplici matrici
di rotazione.

La domanda è: In che modo devo utilizzare i quaternioni per ottenere
rotazioni perfette (nel mio caso, ruotando solo un cubo, niente di
complicato!)?
Senza la SLERP non servono a niente?

Ti posto il mio codice che aggiorna la rotazione:
-----------
protected override void Update(GameTime gameTime)
{
k = Keyboard.GetState();
if (k.IsKeyDown(Keys.Left))
Q = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0),
0.01f)*Q;
if (k.IsKeyDown(Keys.Up))
Q = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0),
0.01f)*Q;

pipeline.World = Matrix.CreateTranslation(-0.5f, -0.5f, -0.5f)
* Matrix.CreateFromQuaternion(Q) * Matrix.CreateTranslation(0.5f, 0.5f,
0.5f);
//In quest'ultima riga (per chi non conosce XNA), si imposta la matrice
che sarà moltiplicata in automatico per tutti i punti del cubo. La prima e
l'ultima traslazione (con 0.5, ecc...) serve per far ruotare il cubo su se
stesso...


base.Update(gameTime);
}

-------------------

Imploro un vostro minimo aiuto soltanto per avere un'idea approssimativa
su come utilizzare i quaternioni.
Nel codice, devo calcolare il cambiamento di orientamento?

--

questo articolo e` stato inviato via web dal servizio gratuito
http://www.newsla... segnala gli abusi ad abuse@newsland.it


Gianpaolo Ingegneri

13/01/2010 21:43:06

0


"Toty_" <marycarl@alice.it> ha scritto nel messaggio
news:hil7t6$gk8$1@news.newsland.it...
> Gianpaolo Ingegneri ha scritto:
>
>> > e la slerp si occuperebbe di eseguire nell'intervallo di
>> > rotazione che va da 0 a 1 tutti i giri intermedi che stanno tra 30 e
>> > 1780
>> > suddividendo sempre in modo da non superare i 180 gradi per
>> > interpolazione.
>
>> mi sono accorto che potrebbe essere frainteso, ma intendevo
>> nell'intervallo
>> di t che va da 0 a 1
>
> Non sto progettando nulla di complicato. Ho appena cominciato con i
> quaternioni in quanto sono incappato nel gimbal lock in un semplice
> programma in cui dovevo ruotare un cubo (attorno all'asse x oppure attorno
> all'asse y, in base al tasto digitato).
> Il problema è che, ad ogni fotogramma, i punti del cubo tornano alle
> coordinate iniziali (in XNA è così) e quindi devo ripetere tutte le
> rotazioni avvenute durante il gioco. Avevo provato moltiplicando un
> quaternione temporaneo per il quaternione globale (che contiene tutte le
> rotazioni avvenute), non c'è più il gimbal lock ma non ruota perfettamente
> e comunque ottengo lo stesso effetto ottenuto usando le semplici matrici
> di rotazione.
>
> La domanda è: In che modo devo utilizzare i quaternioni per ottenere
> rotazioni perfette (nel mio caso, ruotando solo un cubo, niente di
> complicato!)?
> Senza la SLERP non servono a niente?
>
> Ti posto il mio codice che aggiorna la rotazione:
> -----------
> protected override void Update(GameTime gameTime)
> {
> k = Keyboard.GetState();
> if (k.IsKeyDown(Keys.Left))
> Q = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0),
> 0.01f)*Q;
> if (k.IsKeyDown(Keys.Up))
> Q = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0),
> 0.01f)*Q;
>
> pipeline.World = Matrix.CreateTranslation(-0.5f, -0.5f, -0.5f)
> * Matrix.CreateFromQuaternion(Q) * Matrix.CreateTranslation(0.5f, 0.5f,
> 0.5f);
> //In quest'ultima riga (per chi non conosce XNA), si imposta la matrice
> che sarà moltiplicata in automatico per tutti i punti del cubo. La prima e
> l'ultima traslazione (con 0.5, ecc...) serve per far ruotare il cubo su se
> stesso...
>
>
> base.Update(gameTime);
> }
>
> -------------------
>
> Imploro un vostro minimo aiuto soltanto per avere un'idea approssimativa
> su come utilizzare i quaternioni.
> Nel codice, devo calcolare il cambiamento di orientamento?

Questo è molto diverso da quello che chiedevi prima. Prima di tutto separa
la parte dell'input da quella grafica, poi memorizza globalmente due
variabili xrot, yrot ed incrementi solo quelle con l'input della tastiera.
In seguito, nella parte di costruzione delle trasformazioni, crei una
matrice di temp ed una per le trasformazioni finali, per esempio:

CMatrix matTemp, matWorld;
matWorld.Identity();

matTemp.Rotation(0,1,0, yrot)
matWorld = matWorld * matTemp;

matTemp.Rotation(1,0,0, xrot)
matWorld = matWorld * matTemp;

matTemp.Translation(0.5, 0.5, 0.5)
matWorld = matWorld * matTemp;

Ovviamente xrot e yrot li incrementi di 0.01f ad ogni click della tastiera.
Vedrai che i problemi di prima spariranno come per magia ;-) Se non sei
convinto, puoi dare un'occhiata agli esempi di nehe.gamedev.net/ , non sono
XNA ma almeno ti danno le basi per capire tutto il resto.


marycarl

14/01/2010 17:02:04

0

Gianpaolo Ingegneri ha scritto:

> "Toty_" <marycarl@alice.it> ha scritto nel messaggio
> news:hil7t6$gk8$1@news.newsland.it...
> > Gianpaolo Ingegneri ha scritto:
> >
> >> > e la slerp si occuperebbe di eseguire nell'intervallo di
> >> > rotazione che va da 0 a 1 tutti i giri intermedi che stanno tra 30 e
> >> > 1780
> >> > suddividendo sempre in modo da non superare i 180 gradi per
> >> > interpolazione.
> >
> >> mi sono accorto che potrebbe essere frainteso, ma intendevo
> >> nell'intervallo
> >> di t che va da 0 a 1
> >
> > Non sto progettando nulla di complicato. Ho appena cominciato con i
> > quaternioni in quanto sono incappato nel gimbal lock in un semplice
> > programma in cui dovevo ruotare un cubo (attorno all'asse x oppure attorno
> > all'asse y, in base al tasto digitato).
> > Il problema è che, ad ogni fotogramma, i punti del cubo tornano alle
> > coordinate iniziali (in XNA è così) e quindi devo ripetere tutte le
> > rotazioni avvenute durante il gioco. Avevo provato moltiplicando un
> > quaternione temporaneo per il quaternione globale (che contiene tutte le
> > rotazioni avvenute), non c'è più il gimbal lock ma non ruota perfettamente
> > e comunque ottengo lo stesso effetto ottenuto usando le semplici matrici
> > di rotazione.
> >
> > La domanda è: In che modo devo utilizzare i quaternioni per ottenere
> > rotazioni perfette (nel mio caso, ruotando solo un cubo, niente di
> > complicato!)?
> > Senza la SLERP non servono a niente?
> >
> > Ti posto il mio codice che aggiorna la rotazione:
> > -----------
> > protected override void Update(GameTime gameTime)
> > {
> > k = Keyboard.GetState();
> > if (k.IsKeyDown(Keys.Left))
> > Q = Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0),
> > 0.01f)*Q;
> > if (k.IsKeyDown(Keys.Up))
> > Q = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0),
> > 0.01f)*Q;
> >
> > pipeline.World = Matrix.CreateTranslation(-0.5f, -0.5f, -0.5f)
> > * Matrix.CreateFromQuaternion(Q) * Matrix.CreateTranslation(0.5f, 0.5f,
> > 0.5f);
> > //In quest'ultima riga (per chi non conosce XNA), si imposta la matrice
> > che sarà moltiplicata in automatico per tutti i punti del cubo. La prima e
> > l'ultima traslazione (con 0.5, ecc...) serve per far ruotare il cubo su se
> > stesso...
> >
> >
> > base.Update(gameTime);
> > }
> >
> > -------------------
> >
> > Imploro un vostro minimo aiuto soltanto per avere un'idea approssimativa
> > su come utilizzare i quaternioni.
> > Nel codice, devo calcolare il cambiamento di orientamento?

> Questo è molto diverso da quello che chiedevi prima. Prima di tutto separa
> la parte dell'input da quella grafica, poi memorizza globalmente due
> variabili xrot, yrot ed incrementi solo quelle con l'input della tastiera.
> In seguito, nella parte di costruzione delle trasformazioni, crei una
> matrice di temp ed una per le trasformazioni finali, per esempio:

> CMatrix matTemp, matWorld;
> matWorld.Identity();

> matTemp.Rotation(0,1,0, yrot)
> matWorld = matWorld * matTemp;

> matTemp.Rotation(1,0,0, xrot)
> matWorld = matWorld * matTemp;

> matTemp.Translation(0.5, 0.5, 0.5)
> matWorld = matWorld * matTemp;

> Ovviamente xrot e yrot li incrementi di 0.01f ad ogni click della tastiera.
> Vedrai che i problemi di prima spariranno come per magia ;-) Se non sei
> convinto, puoi dare un'occhiata agli esempi di nehe.gamedev.net/ , non sono
> XNA ma almeno ti danno le basi per capire tutto il resto.

Grazie, ho provato ma ho gli stessi e identici risultati (il cubo continua
ad inclinarsi verso l'asse z).

--

questo articolo e` stato inviato via web dal servizio gratuito
http://www.newsla... segnala gli abusi ad abuse@newsland.it


Gianpaolo Ingegneri

14/01/2010 19:06:44

0


> Grazie, ho provato ma ho gli stessi e identici risultati (il cubo continua
> ad inclinarsi verso l'asse z).

in d3d dovresti fare semplicemente:

D3DXMATRIX matWorld;
D3DXMATRIX matTrans;
D3DXMATRIX matRot;

D3DXMatrixTranslation( &matTrans, 0.0f, 0.0f, g_fDistance );
D3DXMatrixRotationYawPitchRoll( &matRot, xrot, yrot, 0.0f );
matWorld = matRot * matTrans;

g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );

Strano che non ti funzioni.


(Matteo Perenzoni)

14/01/2010 21:23:45

0

On Jan 14, 6:02 pm, maryc...@alice.it (Toty_) wrote:
>
> Grazie, ho provato ma ho gli stessi e identici risultati (il cubo continua
> ad inclinarsi verso l'asse z).
>

A questo punto ho il dubbio che in qualche punto non ci siamo
capiti... ti avrei dato la stessa risposta di Gianpaolo.
________________________
Matteo
http://fuzzware.alte...
"A man with a new idea is a crank until the idea succeds" - M. Twain

marycarl

16/01/2010 19:49:27

0

Matteo Perenzoni ha scritto:

> On Jan 14, 6:02 pm, maryc...@alice.it (Toty_) wrote:
> >
> > Grazie, ho provato ma ho gli stessi e identici risultati (il cubo continua
> > ad inclinarsi verso l'asse z).
> >

> A questo punto ho il dubbio che in qualche punto non ci siamo
> capiti... ti avrei dato la stessa risposta di Gianpaolo.
> ________________________
> Matteo
> http://fuzzware.alte...
> "A man with a new idea is a crank until the idea succeds" - M. Twain

Potete vedere il video da questo link:

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

Ruota correttamente (niente gimbal lock) ma il cubo si inclina.

--

questo articolo e` stato inviato via web dal servizio gratuito
http://www.newsla... segnala gli abusi ad abuse@newsland.it


(Matteo Perenzoni)

16/01/2010 21:45:06

0

On 16 Gen, 20:49, maryc...@alice.it (Toty_) wrote:
>
> Potete vedere il video da questo link:
>
> http://www.youtube.com/watch?v=a...
>
> Ruota correttamente (niente gimbal lock) ma il cubo si inclina.
>

Mah, sarò duro e ottuso, ma non capisco dove sia il problema. La
rotazione del cubo mi pare a posto, l'unica cosa che mi può sembrare
una inclinazione dipende dal fatto che il cubo non fa 360 gradi esatti
prima di partire a ruotare sull'altro asse, e per di più sul secondo
asse manca mezzo giro a tornare alla posizione iniziale (fondamentale
per capire se ha perso colpi per strada).
Secondo me il programma è concettualmente corretto, sono le istruzioni
che gli dai che non sono quelle che vorresti dargli :) Potrebbe
essere?
________________________
Matteo
http://fuzzware.alte...
"A man with a new idea is a crank until the idea succeds" - M. Twain