Comment le problème de verrouillage du cardan est-il résolu en utilisant des transformations de matrice accumulatives

12

Je lis le livre en ligne "Learning Modern 3D Graphics Programming" de Jason L. McKesson

À partir de maintenant, je suis au problème du verrouillage du cardan et comment le résoudre en utilisant des quaternions.

Cependant ici, sur la page Quaternions .

Une partie du problème est que nous essayons de stocker une orientation sous la forme d'une série de 3 rotations axiales cumulées. Les orientations sont des orientations, pas des rotations. Et les orientations ne sont certainement pas une série de rotations. Nous devons donc traiter l'orientation du navire comme une orientation, comme une quantité spécifique.

Je suppose que c'est le premier endroit où je commence à être confus, parce que je ne vois pas la différence spectaculaire entre les orientations et les rotations. Je ne comprends pas non plus pourquoi une orientation ne peut pas être représentée par une série de rotations ...

Aussi:

La première pensée à cette fin serait de conserver l'orientation comme matrice. Lorsque vient le temps de modifier l'orientation, nous appliquons simplement une transformation à cette matrice, stockant le résultat en tant que nouvelle orientation actuelle.

Cela signifie que chaque lacet, tangage et roulis appliqué à l'orientation actuelle sera relatif à cette orientation actuelle. C'est précisément ce dont nous avons besoin. Si l'utilisateur applique un lacet positif, vous voulez que ce lacet les fasse pivoter par rapport à l'endroit où ils pointent actuellement, et non par rapport à un système de coordonnées fixe.

Le concept, je le comprends, mais je ne comprends pas comment si l'accumulation de transformations matricielles est une solution à ce problème, comment le code donné dans la page précédente n'est pas seulement cela.

Voici le code:

void display()
{
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClearDepth(1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glutil::MatrixStack currMatrix;
    currMatrix.Translate(glm::vec3(0.0f, 0.0f, -200.0f));
    currMatrix.RotateX(g_angles.fAngleX);
    DrawGimbal(currMatrix, GIMBAL_X_AXIS, glm::vec4(0.4f, 0.4f, 1.0f, 1.0f));
    currMatrix.RotateY(g_angles.fAngleY);
    DrawGimbal(currMatrix, GIMBAL_Y_AXIS, glm::vec4(0.0f, 1.0f, 0.0f, 1.0f));
    currMatrix.RotateZ(g_angles.fAngleZ);
    DrawGimbal(currMatrix, GIMBAL_Z_AXIS, glm::vec4(1.0f, 0.3f, 0.3f, 1.0f));

    glUseProgram(theProgram);
    currMatrix.Scale(3.0, 3.0, 3.0);
    currMatrix.RotateX(-90);
    //Set the base color for this object.
    glUniform4f(baseColorUnif, 1.0, 1.0, 1.0, 1.0);
    glUniformMatrix4fv(modelToCameraMatrixUnif, 1, GL_FALSE, glm::value_ptr(currMatrix.Top()));

    g_pObject->Render("tint");

    glUseProgram(0);

    glutSwapBuffers();
}

À ma connaissance, ce qu'il fait (modifier une matrice sur une pile) n'est-il pas considéré comme accumulant des matrices, car l'auteur a combiné toutes les transformations de rotation individuelles en une seule matrice qui est stockée au sommet de la pile.

Ma compréhension d'une matrice est qu'ils sont utilisés pour prendre un point qui est relatif à une origine (disons ... le modèle), et le faire par rapport à une autre origine (la caméra). Je suis sûr que c'est une définition sûre, mais j'ai l'impression qu'il manque quelque chose qui m'empêche de comprendre ce problème de verrouillage du cardan.

Une chose qui n'a pas de sens pour moi est la suivante: si une matrice détermine la différence relative entre deux "espaces", comment se fait-il qu'une rotation autour de l'axe Y pour, disons, rouler, ne place pas le point dans "l'espace de roulis" "qui peut ensuite être transformé une fois de plus par rapport à ce roulis ... En d'autres termes, aucune autre transformation à ce stade ne devrait être en relation avec ce nouvel" espace de roulis "et donc la rotation ne doit pas être relative à la précédente" espace modèle "qui provoque le verrouillage du cardan.

C'est pourquoi le verrouillage du cardan se produit à droite? C'est parce que nous faisons tourner l'objet autour des axes X, Y et Z définis plutôt que de faire tourner l'objet autour de ses propres axes relatifs . Ou ai-je tort?

Puisqu'apparemment, ce code auquel j'ai lié n'est pas une accumulation de transformations matricielles, pouvez-vous donner un exemple de solution utilisant cette méthode.

Donc en résumé:

  • Quelle est la différence entre une rotation et une orientation?
  • Pourquoi le code n'est-il pas lié dans un exemple d'accumulation de transformations matricielles?
  • Quel est le véritable objectif spécifique d'une matrice, si je me trompais?
  • Comment une solution au problème de verrouillage du cardan pourrait-elle être mise en œuvre en utilisant l'accumulation de transformations matricielles?
  • De plus, en prime: pourquoi les transformations après la rotation sont-elles toujours relatives à "l'espace objet"?
  • Autre bonus: ai-je tort de supposer qu'après une transformation, d'autres transformations se produiront par rapport au courant?

De plus, si ce n'était pas implicite, j'utilise OpenGL, GLSL, C ++ et GLM, donc des exemples et des explications en termes de ceux-ci sont grandement appréciés, sinon nécessaires.

Plus il y a de détails, mieux c'est!

Merci d'avance.

Luke San Antonio Bialecki
la source

Réponses:

11

Je ne suis pas sûr d'un bon moyen de préfacer cela, à part j'espère que cela se rejoindra bien à la fin. Cela dit, plongons-nous dans:

Une rotation et une orientation sont différentes car la première décrit une transformation et la seconde décrit un état. Une rotation est la façon dont un objet entre dans une orientation , et une orientation est l'espace local en rotation de l'objet . Cela peut être directement lié à la façon dont les deux sont représentés mathématiquement: une matrice stocke les transformations d'un espace de coordonnées à un autre (vous l'avez fait correctement), et un quaternion décrit directement une orientation. La matrice ne peut donc décrire que comment l'objet entre dans une orientation , à travers une série de rotations. Le problème avec cela, cependant, est Gimbal Lock.

Le verrouillage du cardan montre la difficulté de placer un objet dans une orientation à l'aide d'une série de rotations. Le problème se produit lorsqu'au moins deux des axes de rotation s'alignent:

Image reproduite avec l'aimable autorisation de deepmesh3d.com
Dans l'image de gauche ci-dessus, les axes bleu et orange font la même rotation! Il s'agit d'un problème, car cela signifie que l'un des trois degrés de liberté a été perdu et que des rotations supplémentaires à partir de ce point peuvent produire des résultats inattendus. L'utilisation de quaternions résout ce problème car appliquer un quaternion pour transformer l'orientation d'un objet mettra directement l'objet dans une nouvelle orientation (c'est la meilleure façon de le dire), plutôt que de décomposer la transformation en opérations de roulis, de tangage et de lacet.

Maintenant, je suis sceptique quant à l'accumulation de matrices étant une solution complète à cela, car l'accumulation de matrices (donc l'accumulation de rotations) est exactement ce qui peut causer le problème de verrouillage du cardan en premier lieu. La bonne façon de gérer la transformation par un quaternion consiste à effectuer une multiplcation de quaternion sur un point:

pTransformed = q * pAsQuaternion * qConjugate

ou en convertissant le quaternion en une matrice et en transformant le point en utilisant cette matrice.

Une rotation de matrice simple (telle qu'un lacet à 45 degrés) sera toujours définie dans l'espace global. Si vous souhaitez appliquer la transformation dans l'espace local, vous devrez transformer votre transformation en cet espace local d'objets. Cela semble étrange, je vais donc élaborer. C'est là que l'importance de l'ordre des rotations entre en jeu. Je recommande de saisir un livre ici afin que vous puissiez suivre les transformations.

Commencez avec le livre à plat, sa couverture dirigée vers le haut au plafond, orientée comme si vous alliez l'ouvrir et commencer à lire. Maintenant, inclinez l'avant du livre de 45 degrés (la couverture avant devrait être à peu près face à vous):

glutil::MatrixStack bookMatrix;
bookMatrix.RotateX(45);

Maintenant, disons que vous vouliez ajuster le lacet du livre à 45 degrés (je pense que je suppose un système de coordonnées droitier, donc cela changera de cap vers la gauche), et vous voulez que cela s'applique à la section locale du livre coordonner l'espace, de sorte que la couverture du livre soit toujours face à vous:

bookMatrix.RotateY(45);

Le problème est que cette rotation se produit dans l'espace de coordonnées global, de sorte que la couverture du livre se terminera face à votre épaule droite. Pour que ce changement de cap se produise dans l'espace de coordonnées local, vous devez d'abord l'avoir appliqué!

glutil::MatrixStack bookMatrix;
bookMatrix.RotateY(45);
bookMatrix.RotateX(45);

Essaye le! Relancez le livre face au plafond. Modifiez son lacet à 45 degrés, puis inclinez-le à 45 degrés le long de l'axe X global (de gauche à droite). C'est l'orientation que vous attendiez avec un pas de 45 et un lacet de 45 dans l'espace local du livre.

Qu'est-ce que ça veut dire? Tout ce qui se résume vraiment, c'est que l'ordre des opérations est important. Les transformations effectuées deviennent d'abord des transformations locales dans le contexte des transformations effectuées par la suite. Cela devient beaucoup pour envelopper votre tête, et c'est ainsi que les quaternions vous épargnent beaucoup de problèmes. Ignorez tout ce qui dépend de la commande.

L'autre énorme avantage des quaternions est qu'ils permettent l'interpolation des orientations. Il est presque impossible d'essayer d'interpoler entre les angles d'Euler en raison des dépendances d'ordre. Les propriétés mathématiques du quaternion permettent une interpolation linéaire sphérique bien définie entre eux.

Pour conclure et répondre à votre question initiale: les transformations de matrice cumulative ne résoudront vraiment pas le problème de verrouillage du cardan, à moins que les transformations soient soigneusement choisies et appliquées dans un ordre précis. Par conséquent, utilisez toujours des quaternions et appliquez des quaternions aux points à l'aide de la multiplication des quaternions.

J'espère que cela t'aides :)

kevintodisco
la source
4
juste pour mémoire, les quaternions peuvent toujours introduire un verrouillage de cardan s'ils sont décrits via les angles d'Euler; comme vous ferez le même calcul d'une manière différente (quaternions plutôt que matrices)
concept3d
1
@ concept3d - félicitations pour avoir mentionné cela! Il est important de comprendre ce qui rend le mécanisme du cardan susceptible de perdre un certain degré de liberté: c'est comme une articulation robotique décrivant intrinsèquement un système d'équations surdéterminé. Si vous construisez ce mécanisme avec des quaternions, des matrices ou de la magie, vous vous retrouvez toujours avec des ambiguïtés - c'est le comprendre et ne pas l'utiliser en premier lieu qui est une vraie solution (sauf si vous êtes obligé de l'utiliser à des fins démonstratives ou techniques) .
teodron
les quaternions sont difficiles à imaginer, la façon dont j'y pense toujours est qu'ils (les quaternions unitaires) représentent un espace à 3 sphères, donc peuvent représenter n'importe quelle orientation, tandis que je comprends que les angles d'Euler représentent chacun des cercles / turos, donc pas une sphère complète cette n'est pas un moyen très précis de représenter l'orientation (3 cercles / tore ne peuvent pas vraiment générer toutes les orientations possibles à moins qu'ils ne tournent indépendamment ce qui n'est pas possible dans le cas des angles d'Euler), je ne sais pas si j'ai expliqué avec précision :)
concept3d
1

Les accumulations matricielles peuvent en fait résoudre le verrouillage du cardan. En accumulant des rotations, vous ajoutez des cardans, permettant toute rotation arbitraire. Le diagramme fourni par ktodisco montre un verrou de cardan dans le diagramme de gauche. La matrice de cette orientation peut être définie comme:

glutil::MatrixStack bookMatrix;
bookMatrix.RotateX(90);
bookMatrix.RotateY(90);
bookMatrix.RotateZ(90);

En raison de la rotation du cardan y, les cardans X et Z sont maintenant verrouillés, nous avons donc perdu un degré de mouvement. À ce stade, nous n'avons pas de lacet (y local, z global) en utilisant ces trois cardans. Mais en ajoutant un autre cardan, je peux tourner localement autour du y:

glutil::MatrixStack bookMatrix;
bookMatrix.RotateX(90);
bookMatrix.RotateY(90);
bookMatrix.RotateZ(90);
bookMatrix.RotateY(90);

Pour chaque nouveau roulis, tangage et lacet, ajoutez simplement un autre cardan, en les cumulant dans une matrice. Ainsi, chaque fois qu'une autre rotation locale est nécessaire, une rotation est créée et multipliée dans la matrice d'accumulation. Comme le chapitre le mentionne, il y a toujours des problèmes, mais le verrouillage du cardan n'en fait pas partie.

Justin Ehrlich
la source