IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

DirectX Discussion :

Caméra, rotation et quaternions


Sujet :

DirectX

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    143
    Détails du profil
    Informations personnelles :
    Localisation : France, Indre et Loire (Centre)

    Informations forums :
    Inscription : Mars 2006
    Messages : 143
    Points : 112
    Points
    112
    Par défaut Caméra, rotation et quaternions
    bonjour

    j'essaye de faire tourner le LookAtPt de ma caméra autour de son axe vertical, lorque j'appuie sur une touche.

    Mais, dés que la rotation atteint PI/2, les axes X et X se confondent et j'obtiens du " gimbal Lock ".

    J 'essaye donc d'utiliser des quaternions, mais j'obtiens quand même du gimbal lock.
    Je ne dois donc pas m'y prendre correctement. voici mon code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
     
    D3DXVec3Cross(&vUpView, &vCam , &g_vRight );	//  calcule Up vecteur de la vue
     
    D3DXQuaternionIdentity( &m_qOrientation);
    D3DXQuaternionRotationAxis ( &m_qOrientation  , &vUpView, thetaY  );	 // fabrique quaternion de rotation		
    D3DXQuaternionNormalize( &m_qOrientation, &m_qOrientation );
    D3DXMatrixRotationQuaternion ( &matOrientation , &m_qOrientation ) ;	// fabrique matrice de rotation
     
    D3DXVec3TransformCoord ( &g_vLookatPt , &g_vLookatPt ,&matOrientation); // applique rotation au LookAtPt
     
    g_FPCamera->SetViewParams( &g_vEyePt , &g_vLookatPt ); // stocke les nouvelles valeurs
    g_matView = *g_FPCamera->GetViewMatrix();	// maj de la matrice de vue
    Si au lieu de faire D3DXVec3TransformCoord (..) sur le LookAtPt, j'effectue un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    g_matView *=matOrientation ; // applique la nouvelle orientation
    g_vLookatPt.x=g_matView._31;	// extrait nouvelles valeurs g_vLookatPt								
    g_vLookatPt.y=g_matView._32;
    g_vLookatPt.z=g_matView._33;
     
    g_vEyePt.x=g_matView._41;		// 	extrait nouvelles valeurs  g_vEyePt												
    g_vEyePt.y=g_matView._42;
    g_vEyePt.z=g_matView._43;
    j'obtiens encore du gimbal lock

    j'ai essayé aussi en fabriquant un quaternion à partir de la vue , et en faisant le produit avec le quaternion de rotation

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    D3DXVec3Cross(&vUpView, &vCam , &g_vRight );	//  calcule Up vecteur de la vue ,identique à l'extraction de matrice de vue ( sauf signe Z )
     
    D3DXQuaternionIdentity( &m_qOrientation);
    D3DXQuaternionRotationAxis ( &m_qOrientation  , &vUpView, thetaY  ) ;		// fabrique quaternion de rotation		
    D3DXQuaternionNormalize( &m_qOrientation, &m_qOrientation );
    D3DXMatrixRotationQuaternion ( &matOrientation , &m_qOrientation ) ;		// fabrique matrice de rotation
     
    D3DXQuaternionRotationMatrix( &m_qView , &g_matView );	
    D3DXQuaternionNormalize( &m_qView, &m_qView );
    m_qView *= m_qOrientation;
    D3DXMatrixRotationQuaternion ( &g_matView , &m_qView ) ; // fabrique matrice de rotation
     
    g_matView *= matOrientation;
     
    g_vLookatPt.x=g_matView._31; // extrait nouvelles valeurs g_vLookatPt								
    g_vLookatPt.y=g_matView._32;
    g_vLookatPt.z=g_matView._33;
     
    g_vEyePt.x=g_matView._41; // 	extrait nouvelles valeurs  g_vEyePt												
    g_vEyePt.y=g_matView._42;
    g_vEyePt.z=g_matView._43;
     
    g_FPCamera->SetViewParams( &g_vEyePt , &g_vLookatPt ); // stocke les nouvelles valeurs
    g_matView = *g_FPCamera->GetViewMatrix();	 // maj de la matrice de vue
    De plus lorsque j'effectue une rotation sur ma matrice de vue, je m'attends à ce que la base de vecteurs de la caméra soit modifiée à chaque demande de rotation, mais dans mon code je dois accroître les valeurs de mon angle de rotation ( thetaY ), pour faire tourner ma caméra.

    J'ai donc vraiment un problème, et je ne m'y prends certainement pas comme il faut.

    un peu d'aide sera bienvenue

    merci

  2. #2
    Membre expérimenté

    Profil pro
    Programmeur
    Inscrit en
    Août 2002
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Programmeur

    Informations forums :
    Inscription : Août 2002
    Messages : 1 091
    Points : 1 679
    Points
    1 679
    Par défaut
    J 'essaye donc d'utiliser des quaternions, mais j'obtiens quand même du gimbal lock.
    Le problème c'est que tu as toujours une représentation 1-1 de Euler vers quaternion.

    Ce qu'il faut que tu fasses c'est que tu convertisses un mouvement incrémental (deltaX -> micro rotation selon l'axe X causé par le mouvement de la souris par exemple) en matrice de rotation (ou quaternion) et que tu combines cette mini rotation à ton orientation courante (stockée sous forme de matrice ou de quaternion) pour obtenir la nouvelle orientation courante.

    N'oublie pas de renormaliser ta matrice ou ton quaternion de temps en temps, parce que les erreurs d'arrondis des nombres flottants vont s'accumuler au fur et à mesure des manipulations et faire que ta matrice ou ton quaternion vont "se rapetisser/s'etendre" ou introduire des déformations autres que des simples rotations.

    Ensuite si tu en as besoin tu peux essayer d'extraire une information de coordonnées d'Euler de ta matrice ou de ton quaternion (il y a toujours un mapping unique de l'un vers l'autre sauf dans la position du gimbal lock où plusieurs angles d'euler peuvent conduire à la même orientation). Mais n'utilise cette donnée qu'à titre d'information et non pas comme représentation principale.

    LeGreg

    Mon site web | Mon blog | Mes photos | Groupe USA
    > BONJOUR, JE SUIS NOUVEAU SUR CE FORUM
    > presse la touche caps lock, stp
    > OH.. MERCI C EST BEAUCOUP PLUS FACILE COMME CA

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    143
    Détails du profil
    Informations personnelles :
    Localisation : France, Indre et Loire (Centre)

    Informations forums :
    Inscription : Mars 2006
    Messages : 143
    Points : 112
    Points
    112
    Par défaut
    Le problème c'est que tu as toujours une représentation 1-1 de Euler vers quaternion.
    Ce qui veut dire ?

    Ce qu'il faut que tu fasses c'est que tu convertisses un mouvement incrémental (deltaX -> micro rotation selon l'axe X causé par le mouvement de la souris par exemple) en matrice de rotation
    J'utilise une telle méthode avec incrément de déplacement souris pour contrôler une rotation à la souris, qui marche bien sans gimbal lock

    voici le code

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
     
    // détection bord ecran 4 pixels pour rotation souris
    if(g_Pos.x<=4) g_fSpinX++;									
    if(g_Pos.x>=GetSystemMetrics(SM_CXSCREEN)-4 ) g_fSpinX--;	
     
    if(g_Pos.y<=4) g_fSpinY--;
    if(g_Pos.y>=GetSystemMetrics(SM_CYSCREEN)-4 ) g_fSpinY++;
     
    if (MOUSEROT_FLAG==true)	// calcul rotation circulaire de vue à la souris, vue  calculée par produit de matrices de rotation puis extraction des valeurs
    {
    D3DXMATRIXA16 matRotX,matRotY,matTrans;
    D3DXVECTOR3 vCam=g_vLookatPt-g_vEyePt;
     
    D3DXMatrixRotationY( &matRotY ,D3DXToRadian(g_fSpinX) ); // sens horizontal g_fSpinX = rotation autour de l'axe Y
    D3DXMatrixRotationX( &matRotX ,D3DXToRadian(g_fSpinY) ); // sens horizontal g_fSpinY = rotation autour de l'axe X
     
    D3DXMatrixIdentity( &matTrans );
    matTrans=matTrans*matRotY*matRotX;	// produit des matrices
     
     matTrans._41=vCam.x 	// stocke vCam dans la matrice de transformation
    matTrans._42=vCam.y;	// g_vEyePt.y;
    matTrans._43=vCam.z;	// g_vEyePt.z; 
     
    g_matView*=matTrans;				// modifie matrice de vue
     
    g_vLookatPt.x=g_matView._31;		// stocke nouvelles valeurs g_vLookatPt								
    g_vLookatPt.y=g_matView._32;
    g_vLookatPt.z=g_matView._33;
     
    // g_vEyePt est conservé												
     
     
    g_FPCamera->SetViewParams( &g_vEyePt , &g_vLookatPt );
    }
    Avec cette méthode les pas angulaires de rotation sont calculés par déplacement souris, et ont donc peu de chance d'être de PI/2 et donc que 2 axes de rotation se confondent.

    Lorsque j'ai implanté cette rotation en début de OnFrameMove(), je me suis retrouvé avec des conflits avec la classe BaseCamera lorsqu'elle gère les touches claviers.

    J'ai donc décider de gérer moi-même le clavier et d'inhiber la gestion clavier par la BaseCamera.

    Et donc en ce qui converne ma rotation par touche clavier, si j'emploie un pas de rotation qui ne soit pas un multiple de PI/2, je ne devrais pas me trouver dans un cas d'alignement de 2 axes.

    Pourtant un pas de PI/113, n'empêche pas le gimbal lock.

    Faut il, aprés une modification du EyePt où du LookAtPt, sortir de onFrameMove() où mettre à jour la caméra via "g_FPCamera->FrameMove( fElapsedTime );" afin que les nouvelles valeurs soit maj immédiatement et que l'on ait une nouvelle matrice de vue pour effectuer la rotation suivante ?

    Les quaternions ne protègent donc pas toujours du gimbal lock ?


  4. #4
    Membre expérimenté

    Profil pro
    Programmeur
    Inscrit en
    Août 2002
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Programmeur

    Informations forums :
    Inscription : Août 2002
    Messages : 1 091
    Points : 1 679
    Points
    1 679
    Par défaut
    Citation Envoyé par korsakoff69 Voir le message
    Les quaternions ne protègent donc pas toujours du gimbal lock ?
    Si tu te mets un préservatif sur la tête, ça ne va pas te protéger du sida.

    Un quaternion c'est juste une représentation compacte d'une orientation (tout comme la matrice 3x3 orthonormalisée et directe), et comme la matrice elle est non ambigue (grâce au quatrième terme) mais est un peu plus compacte qu'une matrice (qui peut représenter plus de transformations différentes). Par contre Euler (ou les angles nautiques ou tout autre représentation à base de trois réels) est ambigu parce que trois réels peuvent certes mapper l'espace des orientations mais possèdent un pôle où la représentation n'est plus unique. Si tu persévères à ne calculer ton orientation depuis ta représentation principale (Euler) qui est ambigue alors tu n'auras résolu aucun problème d'ambiguité.

    En gros je t'explique ce que tu fais (dans ton premier poste):

    "Euler X = orientation x absolue
    Euler Y = orientation y absolue
    Euler Z = orientation z absolue

    Tu calcules un quaternion à partir de tes angles X, Y et Z
    q(X,Y, Z)
    Puis tu calcules une matrice de transformation M(X,Y, Z) - pour la carte graphique - à partir de ton quaternion."

    Donc en toute honnêteté tu aurais pu te passer de la passe avec le quaternion. et calculer directement M(X,Y,Z), ça t'aurait évité des calculs, des erreurs d'arrondis supplémentaires. Mais surtout ça n'aurait pas plus éviter les problèmes de Gimbal lock parce que pour X = pi/2 (par exemple) M(pi/2, Y+k, Z) = M(pi/2, Y, Z+k) et q(pi/2, Y+k, Z) = q(pi/2, Y, Z+k) ou quelque chose du même genre. C'est là l'essence du Gimbal lock, ça n'a rien à voir avec quaternion vs matrice.

    Une solution possible c'est de se passer des angles d'Euler (ou nautiques ou tout autre représentation à base de trois réels) à part pour calculer une matrice intermédiaire (ou quaternion intermédiaire)

    Tu pars de M(t) (Q(t)), matrice (quaternion) à la date t.

    Tu déplaces ta souris de dx, dy.
    ça te donne -> dm(dx, dy), rotation incrémentale.

    La matrice M(t+dt) est donc égale à M(t) multipliée par dm(dx, dy). (t+dt correspond à la frame suivante par exemple ou au time step suivant)
    La représentation M(t) a perdu son appariement aux angles d'Euler parce qu'on l'a calculée par itération. Et M(t) étant une représentation matricielle n'a pas d'orientation ambigue, toute orientation a une représentation matricielle unique (remplace matrice par quaternion).

    Intérêt du quaternion par rapport à matrice :
    - le quaternion est plus compact (4 réels pour représenter une rotation, par rapport à 9 pour une matrice 3x3, la matrice 3x3 a donc des informations redondantes pour une simple orientation). Si tu dois stocker des orientations (sans autre composante, scaling, shearing, etc) alors le quaternion te fait économiser de la mémoire (moins que les angles d'Euler mais voir plus haut, les angles d'Euler sont une représentation ambigue). Aussi il est plus simple de renormaliser un quaternion qu'orthonormaliser une matrice 3x3 (pour contrer les erreurs d'arrondis de réels en nombres à précision flottante) ce qui peut-être important si tu renormalises souvent (plus souvent que tu fais la conversion matrice<->quaternion).

    LeGreg

    Mon site web | Mon blog | Mes photos | Groupe USA
    > BONJOUR, JE SUIS NOUVEAU SUR CE FORUM
    > presse la touche caps lock, stp
    > OH.. MERCI C EST BEAUCOUP PLUS FACILE COMME CA

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    143
    Détails du profil
    Informations personnelles :
    Localisation : France, Indre et Loire (Centre)

    Informations forums :
    Inscription : Mars 2006
    Messages : 143
    Points : 112
    Points
    112
    Par défaut
    C'est vrai , je m'en rends compte ,j'ai trop fait de radiateur durant la géométrie.

    Peux tu m'expliquer ceci plus précisément

    La représentation M(t) a perdu son appariement aux angles d'Euler parce qu'on l'a calculée par itération.
    Je crois comprendre que mon système de calcul est en cause.

    Il faut modifier dynamiquement les transformations de la matrice de vue, où la composer avec une matrice de transformation mise à jour selon des "deltas" de variation.

    à chaque itération , la matrice de tranformation est mise à jour, les variations ne sont pas cumulées, la matrice de vue est alors recalculée , générant une nouvelle matrice indépendante du repère de base

    Est que ceci est correct ?


  6. #6
    Membre expérimenté

    Profil pro
    Programmeur
    Inscrit en
    Août 2002
    Messages
    1 091
    Détails du profil
    Informations personnelles :
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Programmeur

    Informations forums :
    Inscription : Août 2002
    Messages : 1 091
    Points : 1 679
    Points
    1 679
    Par défaut
    Si tu conserves en mémoire uniquement tes matrices concaténées, tu perds la possibilité de réorthonormaliser la composante rotation => modèle qui rétrécit/s'étend et se déforme au cours du temps.

    Il faut donc que tu conserves en mémoire pour chaque objet mobile sa composante rotation (sous forme de matrice 3x3 ou de quaternion 4x1). Puis à chaque frame, tu calcules la matrice/quaternion qui va t'amener de ta rotation courante à ta rotation suivante (avec le dx, dy de la souris par exemple) et multiplier cette matrice/quaternion intermédiaire avec ta matrice quaternion persistante.

    Puis tu concatènes toutes les autres transformations (rotation de la caméra, translation des objets, de la caméra, mise à l'échelle des objets, projection perspective, taille du viewport/frustum etc.) à chaque frame pour obtenir la matrice objet -> monde, ou objet -> vue, ou objet -> viewport. Suivant ce qui est le plus adapté pour toi.

    LeGreg

    Mon site web | Mon blog | Mes photos | Groupe USA
    > BONJOUR, JE SUIS NOUVEAU SUR CE FORUM
    > presse la touche caps lock, stp
    > OH.. MERCI C EST BEAUCOUP PLUS FACILE COMME CA

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    143
    Détails du profil
    Informations personnelles :
    Localisation : France, Indre et Loire (Centre)

    Informations forums :
    Inscription : Mars 2006
    Messages : 143
    Points : 112
    Points
    112
    Par défaut
    je vais me débrouiller avec toutes ces infos

    merci pour toutes tes réponses LeGreg

    c'est cool de parler avec des gens qualifiés
    a+

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Gérer une caméra avec des quaternions
    Par Kromagg dans le forum API graphiques
    Réponses: 5
    Dernier message: 25/03/2014, 19h57
  2. Rotation avec quaternion selon un repère précis
    Par Scheb dans le forum Développement 2D, 3D et Jeux
    Réponses: 1
    Dernier message: 24/03/2013, 13h11
  3. [UDK] Rotation et quaternion
    Par Acropole dans le forum Unreal Engine
    Réponses: 15
    Dernier message: 03/02/2010, 11h24
  4. Problème avec une caméra utilisant les quaternions
    Par Bakura dans le forum Développement 2D, 3D et Jeux
    Réponses: 17
    Dernier message: 15/12/2007, 19h26
  5. Caméra, rotation: problème acos()
    Par Lyana dans le forum GLUT
    Réponses: 6
    Dernier message: 22/11/2007, 10h44

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo