orient.tex

<< Systèmes de coordonnées polaires

Table des matières

Primitives géométriques >>

Chapitre 8

Rotation en trois dimensions

Si vous ne changez pas de direction,
vous risquez de finir là où vous allez.

— Lao Tseu (vers 600–531 av. J.-C.)

Ce chapitre aborde le problème difficile de la description de l’orientation d’un objet en 3D. Il aborde également les concepts étroitement liés de rotation et de déplacement angulaire. Il existe plusieurs façons différentes d’exprimer l’orientation et le déplacement angulaire en 3D. Nous abordons ici les trois méthodes les plus importantes — matrices, angles d’Euler et quaternions — ainsi que deux formes moins connues — axe-angle et carte exponentielle. Pour chaque méthode, nous définissons précisément comment fonctionne la méthode de représentation, et nous discutons des particularités, des avantages et des inconvénients de la méthode.

Différentes techniques sont nécessaires dans différentes circonstances, et chaque technique a ses avantages et ses inconvénients. Il est important de savoir non seulement comment chaque méthode fonctionne, mais aussi quelle technique est la plus appropriée pour une situation particulière et comment convertir entre les représentations.

La discussion sur l’orientation en 3D est divisée en sections comme suit :

Ce chapitre utilise abondamment les termes espace objet et espace droit. Si vous n’êtes pas familier avec ces termes, vous devriez revenir à la section 3.2, où ils ont été introduits pour la première fois.

8.1Qu’est-ce exactement que l’« orientation » ?

Avant de pouvoir commencer à discuter de la façon de décrire l’orientation en 3D, définissons d’abord précisément ce que nous cherchons à décrire. Le terme orientation est lié à d’autres termes similaires, tels que

Intuitivement, nous savons que l’« orientation » d’un objet nous dit essentiellement dans quelle direction l’objet est orienté. Cependant, l’« orientation » n’est pas exactement la même chose que la « direction ».

Par exemple, un vecteur a une direction, mais pas une orientation. La différence est que quand un vecteur pointe dans une certaine direction, on peut tordre le vecteur le long de sa longueur (voir la figure 8.1), et il n’y a pas de changement réel du vecteur, puisqu’un vecteur n’a ni épaisseur ni dimension autre que sa longueur.

image

Figure 8.1 Tordre un vecteur n’entraîne aucun changement appréciable du vecteur

Contrairement à un simple vecteur, considérons un objet, comme un avion à réaction, pointant dans une certaine direction. Si nous tordons l’avion (voir la figure 8.2) de la même façon que nous avons tordu le vecteur, nous allons changer l’orientation de l’avion. Dans la section 8.3, nous appelons cette composante de rotation de l’orientation d’un objet le roulis.

image

Figure 8.2Tordre un objet change son orientation

La différence fondamentale entre direction et orientation se voit concrètement par le fait que nous pouvons paramétrer une direction en 3D avec seulement deux nombres (les angles de coordonnées sphériques — voir la section 7.3.2), alors qu’une orientation nécessite un minimum de trois nombres (angles d’Euler — voir la section 8.3).

La section 2.4.1 a expliqué qu’il est impossible de décrire la position d’un objet en termes absolus — nous devons toujours le faire dans le contexte d’un référentiel spécifique. Lorsque nous avons étudié la relation entre « points » et « vecteurs », nous avons remarqué que spécifier une position revient en fait à spécifier une quantité de translation depuis un autre point de référence donné (généralement l’origine d’un système de coordonnées).

De la même façon, l’orientation ne peut pas être décrite en termes absolus. Tout comme une position est donnée par une translation depuis un point connu, une orientation est donnée par une rotation depuis une orientation de référence connue (souvent appelée orientation « identité » ou « de base »). La quantité de rotation est appelée déplacement angulaire. En d’autres termes, décrire une orientation est mathématiquement équivalent à décrire un déplacement angulaire.

Nous disons « mathématiquement équivalent » parce que dans ce livre, nous faisons une distinction subtile entre « orientation » et des termes comme « déplacement angulaire » et « rotation ». Il est utile de penser à un « déplacement angulaire » comme à un opérateur qui accepte une entrée et produit une sortie. Une direction de transformation particulière est implicite ; par exemple, le déplacement angulaire depuis l’ancienne orientation vers la nouvelle orientation, ou depuis l’espace droit vers l’espace objet. Un exemple de déplacement angulaire est : « Faire tourner de 90o90^{o} autour de l’axe zz . » C’est une action que nous pouvons effectuer sur un vecteur.

Cependant, nous rencontrons fréquemment des variables d’état et d’autres situations dans lesquelles ce cadre d’opérateur entrée/sortie n’est pas utile et une relation parent/enfant est plus naturelle. Nous avons tendance à utiliser le mot « orientation » dans ces situations. Un exemple d’orientation est : « Debout et face à l’est. » Cela décrit un état des choses.

Bien entendu, nous pouvons décrire l’orientation « debout et face à l’est » comme un déplacement angulaire en disant : « Debout, face au nord, puis faire tourner de 90o90^{o} autour de l’axe zz . » Cette distinction entre orientation et déplacement angulaire est similaire à la distinction entre points et vecteurs, deux autres termes qui sont équivalents mathématiquement mais pas identiques conceptuellement. Dans les deux cas, le premier terme est utilisé principalement pour décrire un état unique, et le second est principalement utilisé pour décrire une différence entre deux états. Bien entendu, ces conventions sont purement une question de préférence, mais elles peuvent être utiles.

Vous entendrez peut-être aussi le mot « attitude » pour désigner l’orientation d’un objet, surtout si cet objet est un aéronef.

8.2Forme matricielle

Une façon de décrire l’orientation d’un espace de coordonnées en 3D est d’indiquer dans quelle direction pointent les vecteurs de base de cet espace de coordonnées (les axes +x+ x , +y+ y et +z+ z). Bien entendu, nous ne mesurons pas ces vecteurs dans l’espace de coordonnées que nous cherchons à décrire — par définition, ils sont [1,0,0]\lbrack 1,0,0\rbrack , [0,1,0]\lbrack 0,1,0\rbrack et [0,0,1]\lbrack 0,0,1\rbrack quelle que soit l’orientation de l’espace de coordonnées. Nous devons décrire les vecteurs de base en utilisant un autre espace de coordonnées. En faisant cela, nous avons établi l’orientation relative des deux espaces de coordonnées.

Lorsque ces vecteurs de base sont utilisés pour former les lignes d’une matrice 3×33 \times 3 , nous avons exprimé l’orientation sous forme matricielle.1 Une autre façon de dire tout cela est que nous pouvons exprimer l’orientation relative de deux espaces de coordonnées en donnant une matrice de rotation pouvant être utilisée pour transformer des vecteurs d’un espace de coordonnées à l’autre.

image

Figure 8.3 Définition d’une orientation à l’aide d’une matrice

8.2.1Quelle matrice ?

Nous avons déjà vu comment une matrice peut être utilisée pour transformer des points d’un espace de coordonnées à un autre. Dans la figure 8.3, la matrice dans le coin supérieur droit peut être utilisée pour faire pivoter des points de l’espace objet de l’avion vers l’espace droit. Nous avons extrait les lignes de cette matrice pour mettre en évidence leur relation directe avec les coordonnées des axes du corps de l’avion. La matrice de rotation contient les axes de l’objet, exprimés dans l’espace droit. Simultanément, c’est une matrice de rotation : nous pouvons multiplier des vecteurs ligne par cette matrice pour transformer ces vecteurs des coordonnées de l’espace objet en coordonnées de l’espace droit.

Une question légitime à poser est : Pourquoi la matrice contient-elle les axes du corps exprimés à l’aide des coordonnées de l’espace droit ? Pourquoi pas les axes droits exprimés dans les coordonnées de l’espace objet ? Une autre façon de formuler cela est : Pourquoi avons-nous choisi de donner une matrice de rotation qui transforme les vecteurs de l’espace objet vers l’espace droit ? Pourquoi pas de l’espace droit vers l’espace objet ?

Du point de vue mathématique, cette question est un peu absurde. Comme les matrices de rotation sont orthogonales, leur inverse est la même que leur transposée (voir la section 6.3.2). Ainsi, la décision est entièrement cosmétique.

Mais d’un point de vue pratique, à notre avis, c’est assez important. Le cœur du problème est de savoir si vous pouvez écrire du code qui est intuitif à lire et fonctionne du premier coup, ou si cela demande beaucoup de travail de déchiffrement, ou une connaissance de conventions qui ne sont pas énoncées parce qu’elles sont « évidentes » pour tout le monde sauf vous. Permettez-nous donc une brève digression pour poursuivre une réflexion commencée lorsque nous avons introduit le terme « espace droit » dans la section 3.2.4 concernant les aspects pratiques de ce qui se passe lorsque les mathématiques des transformations d’espace de coordonnées sont traduites en code. Permettez-nous également d’exprimer quelques opinions basées sur nos observations de programmeurs aux prises avec des matrices de rotation. Nous ne nous attendons pas à ce que tout le monde soit d’accord avec nos affirmations, mais nous espérons que chaque lecteur appréciera au moins l’intérêt de considérer ces questions.

Certes, toute bonne bibliothèque mathématique aura une classe de matrice 3×33 \times 3 pouvant représenter n’importe quelle transformation arbitraire, c’est-à-dire qu’elle ne fait aucune hypothèse sur la valeur des éléments de la matrice. (Ou peut-être est-ce une matrice 4×44 \times 4 pouvant faire de la projection, ou une 4×34 \times 3 qui peut faire de la translation mais pas de la projection — ces distinctions ne sont pas importantes ici.) Pour une telle matrice, les opérations sont intrinsèquement exprimées en termes d’un espace de coordonnées d’entrée et d’un espace de coordonnées de sortie. Cela est simplement implicite dans l’idée de multiplication matricielle. Si vous devez passer de la sortie vers l’entrée, vous devez obtenir l’inverse de la matrice.

Il est courant d’utiliser la classe de matrice de transformation générique pour décrire l’orientation d’un objet. Dans ce cas, la rotation est traitée comme n’importe quelle autre transformation. L’interface reste en termes d’espace source et d’espace destination. Malheureusement, dans notre expérience, les deux opérations matricielles suivantes sont de loin les plus couramment utilisées :2

Notez que nous devons pouvoir aller dans les deux sens. Nous n’avons aucune expérience ni preuve que l’une des directions soit significativement plus courante que l’autre. Mais plus important encore, la nature même des opérations et la façon dont les programmeurs pensent aux opérations est en termes d’« espace objet » et d’« espace droit » (ou d’une autre terminologie équivalente, telle que « espace parent » et « espace enfant »). Nous ne pensons pas à elles en termes d’espace source et d’espace destination. C’est dans ce contexte que nous souhaitons considérer la question posée au début de cette section : Quelle matrice devons-nous utiliser ?

Premièrement, nous devrions reculer un peu et nous rappeler la distinction mathematiquement insignifiante mais pourtant conceptuellement importante entre orientation et déplacement angulaire. (Voir les notes de terminologie à la fin de la section 8.1.) Si votre but est de créer une matrice qui effectue un déplacement angulaire spécifique (par exemple, « faire pivoter de 30 degrés autour de l’axe xx »), alors les deux opérations ci-dessus ne sont pas vraiment celles que vous avez en tête, et utiliser une matrice de transformation générique avec sa direction de transformation implicite ne pose pas de problème, donc cette discussion ne s’applique pas. Pour l’instant, nous nous concentrons sur la situation dans laquelle l’orientation d’un objet est stockée comme variable d’état.

Supposons que nous adoptions la politique courante et stockions l’orientation à l’aide de la matrice de transformation générique. Nous sommes obligés de choisir arbitrairement une convention, donc décidons que la multiplication par cette matrice transformera de l’espace objet vers l’espace droit. Si nous avons un vecteur dans l’espace droit et que nous devons l’exprimer en coordonnées de l’espace objet, nous devons multiplier ce vecteur par l’inverse3 de la matrice.

Voyons maintenant comment notre politique affecte le code qui est écrit et lu des centaines de fois par les programmeurs de jeux ordinaires.

Notez que le code ne correspond pas terme à terme aux intentions de haut niveau du programmeur. Cela oblige chaque utilisateur à se rappeler les conventions chaque fois qu’il utilise la matrice. Dans notre expérience, ce style de codage est un facteur contribuant à la difficulté que les débutants ont à apprendre à utiliser les matrices ; ils finissent souvent par transposer et négativer des choses au hasard quand les résultats ne semblent pas corrects.

Nous avons trouvé utile d’avoir une classe de matrice 3×33 \times 3 spéciale utilisée exclusivement pour stocker l’orientation d’un objet, et non pour des transformations arbitraires. La classe suppose, comme invariant, que la matrice est orthogonale, ce qui signifie qu’elle ne contient que de la rotation. (Nous supposerions probablement également que la matrice ne contient pas de réflexion, même si cela est possible dans une matrice orthogonale.) Avec ces hypothèses en place, nous sommes maintenant libres d’effectuer des rotations à l’aide de la matrice à un niveau d’abstraction plus élevé. Nos fonctions d’interface correspondent exactement aux intentions de haut niveau du programmeur. De plus, nous avons supprimé les détails déroutants d’algèbre linéaire liés aux vecteurs ligne versus vecteurs colonne, quel espace est à gauche ou à droite, quelle est la direction normale et laquelle est l’inverse, et ainsi de suite. Ou plutôt, nous avons confiné ces détails aux éléments internes de la classe — la personne qui implémente la classe doit certainement choisir une convention (et espérons-le la documenter). En fait, dans cette classe de matrice spécialisée, les opérations de « multiplier un vecteur » et « inverser cette matrice » ne sont pas très utiles. Nous préconiserions de garder cette classe de matrice dédiée confinée aux opérations en termes d’espace droit et d’espace objet, plutôt que de multiplier un vecteur.

Donc, revenons à la question posée au début de cette section : Quelle matrice devons-nous utiliser ? Notre réponse est : « Cela ne devrait pas avoir d’importance. » Par là, nous voulons dire qu’il y a une façon de concevoir votre code matriciel de telle sorte qu’il puisse être utilisé sans savoir quel choix a été fait. En ce qui concerne le code C++, c’est purement un changement cosmétique. Par exemple, peut-être remplaçons-nous simplement le nom de fonction multiply() par objectToUpright(), et de même, nous remplaçons multiplyByTranspose() par uprightToObject(). La version du code avec des espaces de coordonnées nommés descriptifs est plus facile à lire et à écrire.

8.2.2Matrice des cosinus directeurs

Vous pourriez rencontrer le terme (très classique) de cosinus directeurs dans le contexte de l’utilisation d’une matrice pour décrire l’orientation. Une matrice de cosinus directeurs est la même chose qu’une matrice de rotation ; le terme fait simplement référence à une façon particulière d’interpréter (ou de construire) la matrice, et cette interprétation est intéressante et instructive, donc faisons une pause pour y regarder de plus près. Chaque élément d’une matrice de rotation est égal au produit scalaire d’un axe cardinal dans un espace avec un axe cardinal dans l’autre espace. Par exemple, l’élément central m22m_{22} dans une matrice 3×33 \times 3 donne le produit scalaire que fait l’axe yy dans un espace avec l’axe yy dans l’autre espace.

Plus généralement, supposons que les vecteurs de base d’un espace de coordonnées soient les vecteurs unitaires mutuellement orthogonaux 𝐩\mathbf{p} , 𝐪\mathbf{q} et 𝐫\mathbf{r} , tandis qu’un deuxième espace de coordonnées de même origine a comme base une base différente (mais également orthonormée) 𝐩\mathbf{p}^{\prime} , 𝐪\mathbf{q}^{\prime} et 𝐫\mathbf{r}^{\prime} . (Permettez-nous de rompre avec la convention en supprimant tous les chapeaux des vecteurs unitaires dans cette section, pour éviter une surcharge visuelle distrayante dans les équations.) La matrice de rotation qui fait pivoter les vecteurs ligne du premier espace vers le second peut être construite à partir des cosinus des angles entre chaque paire de vecteurs de base. Bien sûr, le produit scalaire de deux vecteurs unitaires est exactement égal au cosinus de l’angle entre eux, donc le produit matriciel est

𝐯[𝐩𝐩𝐪𝐩𝐫𝐩𝐩𝐪𝐪𝐪𝐫𝐪𝐩𝐫𝐪𝐫𝐫𝐫]=𝐯.\begin{matrix} {\mathbf{v}\left\lbrack \ \begin{matrix} {\mathbf{p} \cdot \mathbf{p}^{\prime}} & {\mathbf{q} \cdot \mathbf{p}^{\prime}} & {\mathbf{r} \cdot \mathbf{p}^{\prime}} \\ {\mathbf{p} \cdot \mathbf{q}^{\prime}} & {\mathbf{q} \cdot \mathbf{q}^{\prime}} & {\mathbf{r} \cdot \mathbf{q}^{\prime}} \\ {\mathbf{p} \cdot \mathbf{r}^{\prime}} & {\mathbf{q} \cdot \mathbf{r}^{\prime}} & {\mathbf{r} \cdot \mathbf{r}^{\prime}} \\ \end{matrix} \right\rbrack = \mathbf{v}^{\prime}.} \\ \end{matrix}

Ces axes peuvent être interprétés comme des entités géométriques plutôt que numériques, donc peu importe quelles coordonnées sont utilisées pour décrire les axes (à condition que nous utilisions le même espace de coordonnées pour les décrire tous), la matrice de rotation sera la même.

Par exemple, supposons que nos axes soient décrits à l’aide de coordonnées relatives à la première base. Alors 𝐩\mathbf{p} , 𝐪\mathbf{q} et 𝐫\mathbf{r} ont les formes triviales [1,0,0]\lbrack 1,0,0\rbrack , [0,1,0]\lbrack 0,1,0\rbrack et [0,0,1]\lbrack 0,0,1\rbrack , respectivement. Les vecteurs de base du second espace, 𝐩\mathbf{p}^{\prime} , 𝐪\mathbf{q}^{\prime} et 𝐫\mathbf{r}^{\prime} , ont des coordonnées arbitraires. Lorsque nous substituons les vecteurs triviaux 𝐩\mathbf{p} , 𝐪\mathbf{q} et 𝐫\mathbf{r} dans la matrice de l’équation (8.1) et développons les produits scalaires, nous obtenons

[[1,0,0]𝐩[0,1,0]𝐩[0,0,1]𝐩[1,0,0]𝐪[0,1,0]𝐪[0,0,1]𝐪[1,0,0]𝐫[0,1,0]𝐫[0,0,1]𝐫]=[pxpypzqxqyqzrxryrz]=[𝐩𝐪𝐫].\left\lbrack \ \begin{matrix} {\lbrack 1,0,0\rbrack \cdot \mathbf{p}^{\prime}} & {\lbrack 0,1,0\rbrack \cdot \mathbf{p}^{\prime}} & {\lbrack 0,0,1\rbrack \cdot \mathbf{p}^{\prime}} \\ {\lbrack 1,0,0\rbrack \cdot \mathbf{q}^{\prime}} & {\lbrack 0,1,0\rbrack \cdot \mathbf{q}^{\prime}} & {\lbrack 0,0,1\rbrack \cdot \mathbf{q}^{\prime}} \\ {\lbrack 1,0,0\rbrack \cdot \mathbf{r}^{\prime}} & {\lbrack 0,1,0\rbrack \cdot \mathbf{r}^{\prime}} & {\lbrack 0,0,1\rbrack \cdot \mathbf{r}^{\prime}} \\ \end{matrix} \right\rbrack = \left\lbrack \ \begin{matrix} p_{x}^{\prime} & p_{y}^{\prime} & p_{z}^{\prime} \\ q_{x}^{\prime} & q_{y}^{\prime} & q_{z}^{\prime} \\ r_{x}^{\prime} & r_{y}^{\prime} & r_{z}^{\prime} \\ \end{matrix} \right\rbrack = \begin{bmatrix} {- \mathbf{p}^{\prime} -} \\ {- \mathbf{q}^{\prime} -} \\ {- \mathbf{r}^{\prime} -} \\ \end{bmatrix}.

En d’autres termes, les lignes de la matrice de rotation sont les vecteurs de base de l’espace de coordonnées de sortie, exprimés à l’aide des coordonnées de l’espace de coordonnées d’entrée. Bien sûr, ce fait n’est pas seulement vrai pour les matrices de rotation, il est vrai pour toutes les matrices de transformation. C’est l’idée centrale du fonctionnement d’une matrice de transformation, qui a été développée dans la section 4.2.

Regardons maintenant l’autre cas. Au lieu d’utiliser des coordonnées relatives à la première base, nous mesurerons tout en utilisant le deuxième espace de coordonnées (l’espace de sortie). Cette fois, 𝐩\mathbf{p}^{\prime} , 𝐪\mathbf{q}^{\prime} et 𝐫\mathbf{r}^{\prime} ont des formes triviales, et 𝐩\mathbf{p} , 𝐪\mathbf{q} et 𝐫\mathbf{r} sont arbitraires. En les insérant dans la matrice des cosinus directeurs, nous obtenons

[𝐩[1,0,0]𝐪[1,0,0]𝐫[1,0,0]𝐩[0,1,0]𝐪[0,1,0]𝐫[0,1,0]𝐩[0,0,1]𝐪[0,0,1]𝐫[0,0,1]]=[pxqxrxpyqyrypzqzrz]=[|||𝐩T𝐪T𝐫T|||].\left\lbrack \ \begin{matrix} {\mathbf{p} \cdot \lbrack 1,0,0\rbrack} & {\mathbf{q} \cdot \lbrack 1,0,0\rbrack} & {\mathbf{r} \cdot \lbrack 1,0,0\rbrack} \\ {\mathbf{p} \cdot \lbrack 0,1,0\rbrack} & {\mathbf{q} \cdot \lbrack 0,1,0\rbrack} & {\mathbf{r} \cdot \lbrack 0,1,0\rbrack} \\ {\mathbf{p} \cdot \lbrack 0,0,1\rbrack} & {\mathbf{q} \cdot \lbrack 0,0,1\rbrack} & {\mathbf{r} \cdot \lbrack 0,0,1\rbrack} \\ \end{matrix} \right\rbrack = \left\lbrack \ \begin{matrix} p_{x} & q_{x} & r_{x} \\ p_{y} & q_{y} & r_{y} \\ p_{z} & q_{z} & r_{z} \\ \end{matrix} \right\rbrack = \begin{bmatrix} | & | & | \\ \mathbf{p}^{T} & \mathbf{q}^{T} & \mathbf{r}^{T} \\ | & | & | \\ \end{bmatrix}.

Cela dit que les colonnes de la matrice de rotation sont formées à partir des vecteurs de base de l’espace d’entrée, exprimés à l’aide des coordonnées de l’espace de sortie. Cela n’est pas vrai des matrices de transformation en général ; cela s’applique uniquement aux matrices orthogonales telles que les matrices de rotation.

Notons également que notre convention est d’utiliser des vecteurs ligne à gauche. Si vous utilisez des vecteurs colonne à droite, les choses seront transposées.

8.2.3Avantages de la forme matricielle

La forme matricielle est une forme très explicite de représentation de l’orientation. Cette nature explicite offre certains avantages.

8.2.4Inconvénients de la forme matricielle

La nature explicite d’une matrice présente certains avantages, comme nous l’avons vu, mais elle utilise neuf nombres pour stocker une orientation, alors qu’il est possible de paramétrer l’orientation avec seulement trois nombres. Les nombres « supplémentaires » dans une matrice peuvent causer certains problèmes.

Considérons ce dernier point plus en détail. Si nous prenons neuf nombres quelconques au hasard et créons une matrice 3×33 \times 3 , il est très peu probable que ces six contraintes soient satisfaites, et donc les neuf nombres ne formeront pas une matrice de rotation valide. En d’autres termes, les matrices peuvent être mal formées, du moins pour les besoins de représentation d’une orientation. Les matrices mal formées peuvent être un problème car elles peuvent entraîner des exceptions numériques, des graphiques étrangement déformés et d’autres comportements inattendus.

Comment pourrait-on se retrouver avec une mauvaise matrice ? Il y a plusieurs façons :

8.2.5Résumé de la forme matricielle

Résumons ce que la section 8.2 a dit sur les matrices.

8.3Angles d’Euler

Une autre méthode courante de représentation de l’orientation est connue sous le nom d’angles d’Euler. (Rappelons qu’Euler se prononce « oy-leur », pas « you-ler ».) La technique tire son nom du célèbre mathématicien qui les a développés, Leonhard Euler (1707–1783). La section 8.3.1 décrit comment fonctionnent les angles d’Euler et aborde les conventions les plus courantes. La section 8.3.2 aborde d’autres conventions pour les angles d’Euler, notamment le système important à axes fixes. Nous considérons les avantages et les inconvénients des angles d’Euler dans les sections 8.3.3 et 8.3.4. La section 8.3.5 résume les concepts les plus importants concernant les angles d’Euler.

Cette section utilise de nombreuses idées, termes et conventions de la section 7.3.2 concernant les coordonnées sphériques.

8.3.1Que sont les angles d’Euler ?

L’idée de base des angles d’Euler est de définir un déplacement angulaire comme une séquence de trois rotations autour de trois axes mutuellement perpendiculaires. Cela semble compliqué, mais c’est en réalité assez intuitif. (En fait, sa facilité d’utilisation par les humains est l’un de ses principaux avantages.)

Ainsi, les angles d’Euler décrivent l’orientation comme trois rotations autour de trois axes mutuellement perpendiculaires. Mais quels axes ? Et dans quel ordre ? Il s’avère que trois axes dans n’importe quel ordre fonctionneront, mais la plupart des gens ont trouvé pratique d’utiliser les axes cardinaux dans un ordre particulier. La convention la plus courante, celle que nous utilisons dans ce livre, est la convention dite « cap-tangage-roulis » pour les angles d’Euler. Dans ce système, une orientation est définie par un angle de cap, un angle de tangage et un angle de roulis.

Avant de définir précisément les termes cap, tangage et roulis, passons brièvement en revue les conventions d’espace de coordonnées que nous utilisons dans ce livre. Nous utilisons un système en main gauche, où +x+ x est vers la droite, +y+ y est vers le haut et +z+ z est vers l’avant. (Consultez la figure 1.15 pour une illustration.) De même, si vous avez oublié comment la rotation positive est définie selon la règle de la main gauche, vous pourriez vouloir revenir à la figure 1.14 pour rafraîchir votre mémoire.

Étant donné des angles de cap, tangage et roulis, nous pouvons déterminer l’orientation décrite par ces angles d’Euler à l’aide d’un processus simple en quatre étapes.

Étape 1.Commencez dans l’orientation « identité » — c’est-à-dire avec les axes de l’espace objet alignés avec les axes droits.
image

Figure 8.4Étape 1 : Un objet dans son orientation identité

Étape 2.Effectuez la rotation de cap, en tournant autour de l’axe yy , comme indiqué dans la figure 8.5. Une rotation positive tourne vers la droite (dans le sens horaire vu d’en haut).
image

Figure 8.5 Étape 2 : Le cap est la première rotation et tourne autour de l’axe vertical

Étape 3.Après application du cap, le tangage mesure la quantité de rotation autour de l’axe xx . Il s’agit de l’axe xx de l’espace objet, pas de l’axe xx droit. En restant cohérent avec la règle de la main gauche, une rotation positive tourne vers le bas. En d’autres termes, le tangage mesure en réalité l’angle de déclinaison. Cela est illustré dans la figure 8.6.
image

Figure 8.6 Étape 3 : Le tangage est la deuxième rotation et tourne autour de l’axe latéral de l’objet

Étape 4.Après application des angles de cap et de tangage, le roulis mesure la quantité de rotation autour de l’axe zz . Là encore, il s’agit de l’axe zz de l’espace objet, pas de l’axe zz original de l’espace droit. La règle de la main gauche dicte que le roulis positif tourne dans le sens antihoraire vu depuis l’origine en regardant vers +z+ z . Cela est illustré dans la figure 8.7.
image

Figure 8.7 Étape 4 : Le roulis est la troisième et dernière rotation et tourne autour de l’axe longitudinal de l’objet

Il peut sembler contradictoire que le roulis positif soit antihoraire, puisque le cap positif est horaire. Mais notez que le cap positif est horaire vu de l’extrémité positive de l’axe vers l’origine, la perspective opposée à celle utilisée lors du jugement horaire/antihoraire pour le roulis. Si nous regardons depuis l’origine vers l’extrémité positive de l’axe yy , alors le cap positif tourne bien dans le sens antihoraire. Ou si nous regardons depuis l’extrémité positive de l’axe zz vers l’origine (en regardant en arrière depuis devant l’objet), alors le roulis positif semble faire tourner l’objet dans le sens horaire. Dans les deux cas, la règle de la main gauche prévaut.

Vous avez maintenant atteint l’orientation décrite par les angles d’Euler. Notez la similitude des étapes 1–3 avec la procédure utilisée dans la section 7.3.2 pour localiser la direction décrite par les angles de coordonnées sphériques. En d’autres termes, nous pouvons considérer le cap et le tangage comme définissant la direction de base que l’objet regarde, et le roulis définissant la quantité de torsion.

8.3.2Autres conventions d’angles d’Euler

Le système cap-tangage-roulis décrit dans la section précédente n’est pas la seule façon de définir une rotation à l’aide de trois angles autour d’axes mutuellement perpendiculaires. Il existe de nombreuses variantes sur ce thème. Certaines de ces différences s’avèrent être purement de nomenclature ; d’autres sont plus significatives. Même si vous aimez nos conventions, nous vous encourageons à ne pas sauter cette section, car des concepts très importants y sont abordés ; ces sujets sont une source de beaucoup de confusion, que nous espérons dissiper.

Tout d’abord, il y a la question triviale de la nomenclature. La variation la plus courante que vous rencontrerez a été popularisée par le domaine de l’aérospatiale, la méthode lacet-tangage-roulis (yaw-pitch-roll).5 Le terme « roulis » est complètement synonyme de « roulis » (bank), et pour tous les besoins ils sont identiques. De même, dans le contexte limité du lacet-tangage-roulis, le terme « lacet » est pratiquement identique au terme cap. (Cependant, dans un sens plus large, le mot « lacet » a en réalité une signification subtilement différente, et c’est cette différence subtile qui motive notre préférence pour le terme cap. Nous abordons cette distinction assez pointilleuse dans un instant, mais pour l’instant lacet et cap sont identiques.) Ainsi, essentiellement le lacet-tangage-roulis est le même système que le cap-tangage-roulis.

D’autres termes moins courants sont souvent utilisés. Le cap est aussi appelé azimut. L’angle vertical que nous appelons tangage est aussi appelé attitude ou élévation. Le dernier angle de rotation, que nous appelons « roulis », est parfois appelé inclinaison ou torsion.

Et, bien sûr, il y a ces mathématiciens pervers qui (motivés par le besoin d’économiser de l’espace lors d’écritures au tableau ?) insistent à agresser vos yeux avec un flot de lettres grecques. Vous pourriez voir l’un quelconque des suivants :

Tout est grec pour nous

(ϕ,θ,ψ)(\phi,\theta,\psi) (ψ,θ,ϕ)(\psi,\theta,\phi)
(Ω,i,ω)(\Omega,i,\omega) (α,βγ)(\alpha,\beta\,\gamma) .

Ce sont bien sûr des différences cosmétiques. Peut-être plus intéressant est le fait que vous entendrez souvent ces mêmes trois mots listés dans l’ordre inverse : roulis-tangage-lacet. (Une recherche rapide sur Google pour « roll pitch yaw » ou « yaw pitch roll » donne de nombreux résultats pour les deux formes, sans qu’aucune ne semble prédominante.) Compte tenu de l’importance de l’ordre des rotations, les gens sont-ils vraiment assez pervers pour choisir de les lister dans l’ordre inverse ? Nous ne nous attardons pas simplement sur la terminologie ici ; les distinctions de pensée suggérées par les différences de terminologie seront en réalité utiles lorsque nous considérerons comment convertir les angles d’Euler en une matrice de rotation. Il s’avère qu’il existe une explication tout à fait raisonnable pour cette convention « inversée » : c’est l’ordre dans lequel nous effectuons réellement les rotations dans un ordinateur !

Le système à axes fixes est très étroitement lié au système d’angles d’Euler. Dans un système d’angles d’Euler, la rotation s’effectue autour des axes du corps, qui changent après chaque rotation. Ainsi, par exemple, l’axe physique de l’angle de roulis est toujours l’axe longitudinal du corps en espace objet, mais en général il est orienté de façon arbitraire dans l’espace droit. Dans un système à axes fixes, en revanche, les axes de rotation sont toujours les axes droits fixes. Mais il s’avère que le système à axes fixes et le système d’angles d’Euler sont en réalité équivalents, à condition que nous effectuions les rotations dans l’ordre inverse.

Vous devriez visualiser l’exemple suivant pour vous convaincre que c’est vrai. Disons que nous avons un cap de hh et un tangage de pp . (Nous ignorons le roulis pour l’instant.) Selon la convention des angles d’Euler, nous effectuons d’abord la rotation autour de l’axe de cap et tournons de hh autour de l’axe vertical (l’axe yy). Puis nous tournons autour de l’axe latéral de l’espace objet (l’axe xx) d’un angle pp . Avec un schéma à axes fixes, nous arrivons à cette même orientation finale en effectuant les rotations dans l’ordre inverse. D’abord, nous effectuons le tangage, en tournant autour de l’axe xx droit de pp . Ensuite, nous effectuons la rotation de cap, en tournant autour de l’axe yy droit de hh . Bien que nous puissions visualiser les angles d’Euler, à l’intérieur d’un ordinateur lorsque nous faisons pivoter des vecteurs de l’espace droit vers l’espace objet, nous utilisons en réalité un système à axes fixes. Nous en discutons plus en détail dans la section 8.7.1, où nous montrons comment convertir des angles d’Euler en une matrice de rotation. Les conventions à axes fixes sont également appelées extrinsèques, les conventions d’angles d’Euler typiques étant appelées intrinsèques.

Les angles d’Euler tournent autour des axes du corps, de sorte que l’axe de rotation d’une étape donnée dépend des angles utilisés dans les rotations précédentes. Dans le système à axes fixes, les axes de rotation sont toujours les mêmes — les axes droits. Les deux systèmes sont équivalents, à condition que les rotations soient effectuées dans l’ordre inverse.

Nous voudrions maintenant mener une brève mais humble campagne en faveur d’une utilisation plus précise du terme « lacet ». Beaucoup de terminologie aéronautique est héritée de la terminologie nautique.6 Dans un contexte nautique, le sens original du mot « lacet » était essentiellement la même chose que le cap, à la fois en termes d’angle absolu et de changement de cet angle. Dans le contexte des avions et d’autres corps en rotation libre, cependant, nous ne pensons pas que le lacet et le cap soient la même chose. Un mouvement de lacet produit une rotation autour de l’axe yy de l’objet, alors qu’un changement de cap produit une rotation autour de l’axe yy droit. Par exemple, lorsqu’un pilote d’avion utilise les pédales pour contrôler le gouvernail de direction, il effectue une rotation de lacet, car la rotation causée par le gouvernail est toujours autour de l’axe yy de l’espace objet de l’avion. Imaginez un avion plongeant tout droit vers le bas. Si le pilote effectue un lacet de 90o90^{o} , l’avion se retrouvera « sur l’oreille », ne regardant plus vers le bas, mais vers l’horizon, avec un roulis de 90o90^{o} . Cela est illustré dans la figure 8.8.

image

Figure 8.8Cap versus lacet

En revanche, lorsque des joueurs navigant dans un jeu de tir à la première personne bougent la souris de gauche à droite, ils effectuent une rotation de cap. La rotation est toujours autour de l’axe vertical (l’axe yy droit). Si les joueurs regardent vers le bas et bougent la souris horizontalement pour effectuer une rotation de cap, ils continuent à regarder vers le bas et tournent sur place. L’important n’est certainement pas que le cap soit meilleur que le lacet parce que c’est ce que nous faisons dans les jeux de tir à la première personne. L’important est qu’un mouvement de lacet ne peut pas être accompli en ajustant un seul angle d’Euler, alors qu’un mouvement de cap peut l’être. C’est pourquoi nous pensons que « cap » est un meilleur terme : c’est l’action qui résulte lorsque vous effectuez un changement incrémental au premier angle d’Euler.

Hélas, le même argument peut être avancé contre le terme « tangage ». Si le roulis est non nul, un changement incrémental du deuxième angle d’Euler ne produit pas une rotation autour de l’axe latéral de l’objet. Mais il n’existe pas vraiment de mot simple et bon pour décrire l’angle que l’axe longitudinal de l’objet fait avec l’horizontale, ce qui est ce que le deuxième angle d’Euler spécifie vraiment. (« Inclinaison » ne convient pas car elle est spécifique aux conventions en main droite.)

Nous espérons que vous avez lu nos opinions avec l’humilité que nous avions l’intention d’y mettre, et que vous avez également reçu le message plus important : l’investigation de différences de convention (apparemment cosmétiques) peut parfois nous mener à une compréhension plus profonde des points subtils. Et parfois c’est simplement du pinaillage. Des générations d’ingénieurs aéronautiques ont mis des hommes sur la lune et des robots sur Mars, et construit des avions transportant en toute sécurité les auteurs vers et depuis des villes lointaines, en utilisant tout ce temps les termes lacet et roulis. Vous ne croiriez pas que certains de ces gars ne savent même pas qui nous sommes !? Face au choix de votre propre terminologie, nous disons d’utiliser le mot « cap » quand vous pouvez, mais si vous entendez le mot « lacet », pour l’amour de tout, n’en faites pas autant de cas que nous le faisons dans ces pages, surtout si la personne à qui vous parlez est plus intelligente que vous.

Bien que dans ce livre nous ne suivions pas les conventions de coordonnées aérospatiales en main droite (et que nous ayons un léger désaccord sur la terminologie), en ce qui concerne la stratégie de base des angles d’Euler, dans un sens physique, nous pensons qu’une conformité totale avec la sagesse des pères fondateurs de l’aérospatiale est la seule voie à suivre, du moins si votre univers a une notion de « sol ». Rappelons qu’en théorie, trois axes quelconques peuvent être utilisés comme axes de rotation, dans n’importe quel ordre. Mais vraiment, les conventions qu’ils ont choisies sont les seules qui ont un sens pratique, si vous voulez que les angles individuels soient utiles et significatifs. Peu importe comment vous étiquetez vos axes, le premier angle doit tourner autour de la verticale, le second autour de l’axe latéral du corps, et le troisième autour de l’axe longitudinal du corps.

Comme si tout cela ne suffisait pas, ajoutons-en encore quelques-unes. Dans le système que nous avons décrit, chaque rotation s’effectue autour d’un axe du corps différent. Cependant, le propre système original d’Euler était un système « symétrique » dans lequel les première et dernière rotations s’effectuent autour du même axe. Ces méthodes sont plus pratiques dans certaines situations, comme la description du mouvement d’une toupie, où les trois angles correspondent à la précession, la nutation et le spin. Vous pourriez rencontrer certains puristes qui s’opposent au nom « angles d’Euler » attaché à un système asymétrique, mais cet usage est répandu dans de nombreux domaines, donc soyez assuré que vous les surpassez en nombre. Pour distinguer les deux systèmes, les angles d’Euler symétriques sont parfois appelés angles d’Euler « propres », les conventions plus courantes étant appelées angles de Tait-Bryan, documentés pour la première fois par les pères fondateurs de l’aérospatiale que nous avons mentionnés [1]. O’Reilly [10] aborde les angles d’Euler propres et encore plus de méthodes pour décrire la rotation, comme le vecteur de Rodrigues, les paramètres de Cayley-Klein, et des remarques historiques intéressantes. Le résumé de James Diebel [3] compare différentes conventions d’angles d’Euler et les autres méthodes principales pour décrire la rotation, tout comme le fait ce chapitre, mais suppose un niveau plus élevé de sophistication mathématique.

Si vous devez travailler avec des angles d’Euler qui utilisent une convention différente de celle que vous préférez, nous offrons deux conseils :

8.3.3Avantages des angles d’Euler

Les angles d’Euler paramétrisent l’orientation en utilisant seulement trois nombres, et ces nombres sont des angles. Ces deux caractéristiques des angles d’Euler présentent certains avantages par rapport à d’autres formes de représentation de l’orientation.

8.3.4Inconvénients des angles d’Euler

Cette section aborde certains inconvénients de la méthode des angles d’Euler pour représenter l’orientation ; principalement :

Abordons ces points en détail. Premièrement, nous avons le problème que pour une orientation donnée, il existe de nombreux triplets d’angles d’Euler différents pouvant être utilisés pour décrire cette orientation. C’est ce qu’on appelle l’aliasage et cela peut être une inconvénience. Ces problèmes irritants sont très similaires à ceux rencontrés lors de la gestion des coordonnées sphériques dans la section 7.3.4. Des questions basiques comme « Deux triplets d’angles d’Euler représentent-ils le même déplacement angulaire ? » sont difficiles à répondre en raison de l’aliasage.

Nous avons déjà vu un type trivial d’aliasage avec les coordonnées polaires : ajouter un multiple de 360o360^{o} ne change pas l’orientation exprimée, même si les nombres sont différents.

Une deuxième forme d’aliasage plus gênante se produit parce que les trois angles ne sont pas complètement indépendants les uns des autres. Par exemple, un tangage vers le bas de 135° équivaut à un cap de 180°, un tangage vers le bas de 45°, puis un roulis de 180°.

Pour traiter l’aliasage des coordonnées sphériques, nous avons trouvé utile d’établir un ensemble canonique ; tout point donné a une représentation unique dans l’ensemble canonique qui est la façon « officielle » de décrire ce point en coordonnées polaires. Nous utilisons une technique similaire pour les angles d’Euler. Afin de garantir une représentation unique en angles d’Euler pour toute orientation donnée, nous restreignons les plages des angles. Une technique courante consiste à limiter le cap et le roulis à (180o,+180o]( - 180^{o},{+ 180^{o}}\rbrack et à limiter le tangage à [90o,+90o]\lbrack - 90^{o},{+ 90^{o}}\rbrack . Pour toute orientation, il n’existe qu’un seul triplet d’angles d’Euler dans l’ensemble canonique représentant cette orientation. (En réalité, il y a une singularité supplémentaire irritante qui doit être traitée, que nous décrivons dans un instant.) L’utilisation d’angles d’Euler canoniques simplifie beaucoup de tests de base comme « est-ce que je fais approximativement face à l’est ? »

Le type d’aliasage le plus célèbre (et irritant) dont souffrent les angles d’Euler est illustré par cet exemple : si nous nous orientons à droite de 45o45^{o} de cap et que nous nous penchons vers le bas de 90o90^{o} de tangage, c’est identique à un tangage vers le bas de 90° puis un roulis de 45°. En fait, une fois que nous choisissons ±90o\pm 90^{o} comme angle de tangage, nous sommes restreints à tourner autour de l’axe vertical. Ce phénomène, dans lequel un angle de ±90o\pm 90^{o} pour la deuxième rotation peut amener les première et troisième rotations à tourner autour du même axe, est connu sous le nom de blocage de cardan. Pour supprimer cet aliasage de l’ensemble canonique des triplets d’angles d’Euler, nous assignons toute rotation autour de l’axe vertical au cap dans le cas de blocage de cardan. En d’autres termes, dans l’ensemble canonique, si le tangage est ±90o\pm 90^{o} , alors le roulis est zéro.

Cette dernière règle pour le blocage de cardan complète les règles pour l’ensemble canonique des angles d’Euler :

Conditions satisfaites par les angles d’Euler dans l’ensemble canonique

180o<h180o90op90o180o<b180op=±90ob=0.\begin{matrix} {- 180^{o} < h \leq 180^{o}} \\ {- 90^{o} \leq p \leq 90^{o}} \\ {- 180^{o} < b \leq 180^{o}} \\ {p = {\pm 90^{o}}\ \ \Rightarrow\ \ b = 0.} \\ \end{matrix}

Lors de l’écriture de code C++ acceptant des arguments d’angles d’Euler, il est généralement préférable de s’assurer qu’il fonctionne avec des angles d’Euler dans n’importe quelle plage. Heureusement, c’est généralement facile ; les choses fonctionnent souvent sans prendre de précautions supplémentaires, surtout si les angles sont passés à des fonctions trigonométriques. Cependant, lors de l’écriture de code qui calcule ou retourne des angles d’Euler, il est bonne pratique de retourner le triplet d’angles d’Euler canonique. Les méthodes de conversion présentées dans la section 8.7 illustrent ces principes.

image

Figure 8.9 L’interpolation naïve peut causer une rotation excessive

Une idée fausse courante est que, en raison du blocage de cardan, certaines orientations ne peuvent pas être décrites avec des angles d’Euler. En réalité, pour les besoins de description d’une orientation, l’aliasage ne pose aucun problème. Pour être clair, n’importe quelle orientation en 3D peut être décrite avec des angles d’Euler, et cette représentation est unique dans l’ensemble canonique. De plus, comme nous l’avons mentionné dans la section précédente, il n’existe pas d’ensemble d’angles d’Euler « invalide ». Même si les angles sont hors de la plage habituelle, nous pouvons toujours nous mettre d’accord sur l’orientation décrite par les angles d’Euler.

Donc pour les besoins de simplement décrire l’orientation, l’aliasage n’est pas un problème majeur, surtout lorsque des angles d’Euler canoniques sont utilisés. Alors qu’est-ce qui est si mauvais dans l’aliasage et le blocage de cardan ? Disons que nous souhaitons interpoler entre deux orientations 𝐑0\mathbf{R}_{0} et 𝐑1\mathbf{R}_{1} . En d’autres termes, pour un paramètre tt donné, 0t10 \leq t \leq 1 , nous souhaitons calculer une orientation intermédiaire 𝐑(t)\mathbf{R}(t) qui interpole régulièrement de 𝐑0\mathbf{R}_{0} à 𝐑1\mathbf{R}_{1} à mesure que tt varie de 00 à 11 . C’est une opération extrêmement utile pour l’animation de personnages et le contrôle de caméra, par exemple.

image

Figure 8.10 L’interpolation naïve peut faire la rotation par le long chemin.

L’approche naïve à ce problème consiste à appliquer la formule d’interpolation linéaire standard (« lerp ») à chacun des trois angles indépendamment :

Interpolation linéaire simple entre deux angles

Δθ=θ1θ0,θt=θ0+tΔθ.\begin{matrix} {\Delta\theta} & {= \theta_{1} - \theta_{0},} \\ \theta_{t} & {= \theta_{0} + t\,\Delta\theta.} \\ \end{matrix}

Cela est plein de problèmes.

Premièrement, si des angles d’Euler canoniques ne sont pas utilisés, nous pouvons avoir de grandes valeurs d’angles. Par exemple, imaginez que le cap de 𝐑0\mathbf{R}_{0} , noté h0h_{0} , soit 720°. Supposons que h1=45oh_{1} = 45^{o} . Or, 720o=2×360o720^{o} = 2 \times 360^{o} , ce qui équivaut à 0°, donc essentiellement h1h_{1} et h2h_{2} ne sont qu’à 45° l’un de l’autre. Cependant, l’interpolation naïve fera presque deux tours dans la mauvaise direction, comme indiqué dans la figure 8.9.

Bien sûr, la solution à ce problème est d’utiliser des angles d’Euler canoniques. Nous pourrions supposer que nous interpolons toujours entre deux ensembles d’angles d’Euler canoniques. Ou nous pourrions tenter d’imposer cela en convertissant en valeurs canoniques dans notre routine d’interpolation. (Envelopper simplement les angles dans la plage (180o,+180o]( - 180^{o},{+ 180^{o}}\rbrack est facile, mais traiter les valeurs de tangage hors de la plage [90o,+90o]\lbrack - 90^{o},{+ 90^{o}}\rbrack est plus difficile.)

Cependant, même l’utilisation d’angles canoniques ne résout pas complètement le problème. Un deuxième type de problème d’interpolation peut se produire à cause de la nature cyclique des angles de rotation. Supposons que h0=170oh_{0} = - 170^{o} et h1=170oh_{1} = 170^{o} . Notez que ce sont des valeurs canoniques pour le cap, toutes deux dans la plage (180o,+180o]( - 180^{o},{+ 180^{o}}\rbrack . Les deux valeurs de cap ne sont qu’à 20o20^{o} l’une de l’autre, mais là encore, l’interpolation naïve ne se comportera pas correctement, effectuant la rotation par le long chemin avec une rotation horaire de 340o340^{o} au lieu de prendre le chemin plus court antihoraire de 20o20^{o} , comme indiqué dans la figure 8.10.

La solution à ce deuxième type de problème est d’envelopper les différences entre les angles utilisés dans l’équation d’interpolation dans la plage (180o,+180o]( - 180^{o},{+ 180^{o}}\rbrack afin de trouver l’arc le plus court. Pour ce faire, nous introduisons la notation

Enveloppement d’un angle entre ±180𝐨\pm 180\mathbf{}^{\mathbf{o}}

wrapPi(x)=x360o(x+180o)/360o,{wrapPi}(x) = x - 360^{o}\lfloor{(x + 180^{o})/360^{o}}\rfloor,

\lfloor \cdot \rfloor désigne la fonction plancher.

La fonction wrapPiwrapPi est un petit outil précis que tout programmeur de jeux devrait avoir dans sa boîte à outils. Elle gère élégamment les situations courantes dans lesquelles nous devons tenir compte de la nature cyclique des angles. Elle fonctionne en ajoutant ou soustrayant le multiple approprié de 360o360^{o} . Le listing 8.1 montre comment elle serait implémentée en C.

float wrapPi(float theta) {

    // Vérifier si déjà dans la plage. Ce n'est pas strictement
    // nécessaire, mais ce sera une situation très courante. Nous
    // ne voulons pas subir une perte de vitesse et peut-être de
    // précision en virgule flottante si ce n'est pas nécessaire.
    if (fabs(theta) <= PI) {

        // Une révolution est 2 PI.
        const float TWOPPI = 2.0f*PI;

        // Hors plage. Déterminer combien de "révolutions"
        // nous devons ajouter.
        float revolutions = floor((theta + PI) * (1.0f/TWOPPI));

        // Soustraire
        theta -= revolutions*TWOPPI;
    }

    return theta;
}

Revenons aux angles d’Euler. Comme prévu, l’utilisation de wrapPi(){wrapPi}() facilite la prise du chemin le plus court lors de l’interpolation entre deux angles :

Prendre le chemin le plus court lors de l’interpolation entre deux angles

Δθ=wrapPi(θ1θ0),θt=θ0+tΔθ.\begin{matrix} {\Delta\theta} & {= {wrapPi}(\theta_{1} - \theta_{0}),} \\ \theta_{t} & {= \theta_{0} + t\,\Delta\theta.} \\ \end{matrix}

Mais même avec ces deux pansements, l’interpolation des angles d’Euler souffre toujours du blocage de cardan, qui dans de nombreuses situations provoque un parcours saccadé et non naturel. L’objet pivote soudainement et semble bloqué quelque part. Le problème de base est que la vitesse angulaire n’est pas constante pendant l’interpolation. Si vous n’avez jamais vu à quoi ressemble le blocage de cardan, vous vous demandez peut-être pourquoi tout ce tapage. Malheureusement, il est très difficile d’apprécier pleinement le problème à partir d’illustrations dans un livre — vous devez l’expérimenter en temps réel. Heureusement, cependant, il est facile de trouver une animation illustrant le problème : faites simplement une recherche sur youtube.com pour « gimbal lock ».

Les deux premiers problèmes avec l’interpolation des angles d’Euler étaient irritants, mais certainement pas insurmontables. Les angles d’Euler canoniques et wrapPiwrapPi fournissent des solutions de contournement relativement simples. Le blocage de cardan, malheureusement, est plus qu’un inconvénient mineur ; c’est un problème fondamental. Pourrait-on peut-être reformuler nos rotations et concevoir un système qui ne souffre pas de ces problèmes ? Malheureusement, ce n’est pas possible. Il y a simplement un problème inhérent à l’utilisation de trois nombres pour décrire l’orientation 3D. Nous pourrions changer nos problèmes, mais pas les éliminer. Tout système qui paramétrise l’orientation en 3D en utilisant trois nombres est garanti d’avoir des singularités dans l’espace de paramétrage et donc d’être sujet à des problèmes comme le blocage de cardan. La forme carte exponentielle (voir la section 8.4), un schéma différent pour paramétrer la rotation 3D avec trois nombres, parvient à concentrer les singularités en un seul point : les antipodes. Ce comportement est plus bénin pour certaines situations pratiques, mais il ne supprime pas complètement les singularités. Pour ce faire, nous devons utiliser des quaternions, abordés dans la section 8.5.

8.3.5Résumé des angles d’Euler

Résumons nos conclusions de la section 8.3 sur les angles d’Euler.

8.4Représentations axe-angle et carte exponentielle

Le nom d’Euler est attaché à toutes sortes de choses liées à la rotation (nous venons de discuter des angles d’Euler dans la section 8.3). Son nom est également attaché au théorème de rotation d’Euler, qui dit essentiellement que tout déplacement angulaire 3D peut être accompli via une seule rotation autour d’un axe soigneusement choisi. Pour être plus précis, étant donné deux orientations quelconques 𝐑1\mathbf{R}_{1} et 𝐑2\mathbf{R}_{2} , il existe un axe 𝐧̂\hat{\mathbf{n}} tel que nous pouvons passer de 𝐑1\mathbf{R}_{1} à 𝐑2\mathbf{R}_{2} en effectuant une rotation autour de 𝐧̂\hat{\mathbf{n}} . Avec les angles d’Euler, nous avons besoin de trois rotations pour décrire toute orientation, car nous sommes restreints à tourner autour des axes cardinaux. Cependant, lorsque nous sommes libres de choisir l’axe de rotation, il est possible d’en trouver un tel qu’une seule rotation est nécessaire. De plus, comme nous le montrerons dans cette section, à quelques détails mineurs près, cet axe de rotation est uniquement déterminé.

Le théorème de rotation d’Euler conduit à deux méthodes étroitement liées pour décrire l’orientation. Commençons par quelques notations. Supposons que nous ayons choisi un angle de rotation θ\theta et un axe de rotation passant par l’origine et parallèle au vecteur unitaire 𝐧̂\hat{\mathbf{n}} . (Dans ce livre, la rotation positive est définie selon la règle de la main gauche ; voir la section 1.3.3.)

En prenant les deux valeurs 𝐧̂\hat{\mathbf{n}} et θ\theta telles quelles, nous avons décrit un déplacement angulaire sous la forme axe-angle. Alternativement, comme 𝐧̂\hat{\mathbf{n}} a une longueur unitaire, nous pouvons le multiplier par θ\theta sans perte d’information, donnant le vecteur unique 𝐞=θ𝐧̂\mathbf{e} = \theta\hat{\mathbf{n}} . Ce schéma pour décrire la rotation porte le nom plutôt intimidant et obscur de carte exponentielle.8 L’angle de rotation peut être déduit de la longueur de 𝐞\mathbf{e} ; en d’autres termes, θ=𝐞\theta = {\parallel \mathbf{e} \parallel} , et l’axe est obtenu en normalisant 𝐞\mathbf{e} . La carte exponentielle est non seulement plus compacte que l’axe-angle (trois nombres au lieu de quatre), mais elle évite élégamment certaines singularités et possède de meilleures propriétés d’interpolation et de différentiation.

Nous n’allons pas aborder les formes axe-angle et carte exponentielle avec autant de détails que les autres méthodes de représentation de l’orientation, car en pratique leur utilisation est un peu spécialisée. Le format axe-angle est principalement un outil conceptuel. Il est important à comprendre, mais la méthode obtient relativement peu d’utilisation directe par rapport aux autres formats. Sa capacité notable est que nous pouvons directement obtenir un multiple arbitraire du déplacement. Par exemple, étant donné une rotation en format axe-angle, nous pouvons obtenir une rotation représentant le tiers de la rotation ou 2,65 fois la rotation, simplement en multipliant θ\theta par le montant approprié. Bien sûr, nous pouvons effectuer cette même opération avec la carte exponentielle tout aussi facilement. Les quaternions peuvent faire cela par exponentiation, mais une inspection des mathématiques révèle qu’ils utilisent vraiment le format axe-angle sous le capot. (Même si les quaternions prétendent utiliser la carte exponentielle sous le capot !) Les quaternions peuvent également effectuer une opération similaire en utilisant slerp, mais d’une façon plus indirecte et sans la capacité pour les résultats intermédiaires de stocker des rotations au-delà de 180 degrés. Nous examinerons les quaternions dans la section 8.5.

La carte exponentielle est plus utilisée que l’axe-angle. Tout d’abord, ses propriétés d’interpolation sont meilleures que celles des angles d’Euler. Bien qu’elle ait des singularités (abordées ci-après), elles ne sont pas aussi gênantes que pour les angles d’Euler. Généralement, quand on pense à l’interpolation des rotations, on pense immédiatement aux quaternions ; cependant, pour certaines applications, comme le stockage de données d’animation, la carte exponentielle sous-estimée peut être une alternative viable [5]. Mais l’utilisation la plus importante et la plus fréquente de la carte exponentielle est de stocker non pas le déplacement angulaire, mais la vitesse angulaire. C’est parce que la carte exponentielle se différentie bien (ce qui est quelque peu lié à ses meilleures propriétés d’interpolation) et peut représenter facilement des rotations multiples.

Comme les angles d’Euler, les formes axe-angle et carte exponentielle présentent des aliasages et des singularités, bien que d’une manière légèrement plus restreinte et bénigne. Il y a une singularité évidente à l’orientation identité, ou à la quantité « aucun déplacement angulaire ». Dans ce cas, θ=0\theta = 0 , et notre choix d’axe est sans importance — n’importe quel axe peut être utilisé. Notez cependant que la carte exponentielle cache élégamment cette singularité, puisque la multiplication par θ\theta fait disparaître 𝐞\mathbf{e} , peu importe quel axe de rotation 𝐧̂\hat{\mathbf{n}} est choisi. Une autre forme triviale d’aliasage dans l’espace axe-angle peut être produite en niant à la fois θ\theta et 𝐧̂\hat{\mathbf{n}} . Cependant, la carte exponentielle esquive également ce problème, puisque négativer à la fois θ\theta et 𝐧̂\hat{\mathbf{n}} laisse 𝐞=θ𝐧̂\mathbf{e} = \theta\hat{\mathbf{n}} inchangé !

Les autres alias ne peuvent pas être aussi facilement éliminés. Comme avec les angles d’Euler, l’ajout d’un multiple de 360o360^{o} à θ\theta produit un déplacement angulaire résultant dans la même orientation finale, et cette forme d’aliasage affecte à la fois l’axe-angle et la carte exponentielle. Cependant, ce n’est pas toujours un inconvénient — pour décrire la vitesse angulaire, cette capacité à représenter une telle rotation « supplémentaire » est une propriété importante et utile. Par exemple, il est tout à fait important de pouvoir distinguer une rotation autour de l’axe xx à une vitesse de 720o720^{o} par seconde d’une rotation autour du même axe à une vitesse de 1080o1080^{o} par seconde, même si ces déplacements résultent dans la même orientation finale lorsqu’ils sont appliqués pendant un nombre entier de secondes. Il n’est pas possible de capturer cette distinction en format quaternion.

Il s’avère que, étant donné tout déplacement angulaire pouvant être décrit par une matrice de rotation, la représentation en carte exponentielle est uniquement déterminée. Bien que plus d’une carte exponentielle puisse produire la même matrice de rotation, il est possible de prendre un sous-ensemble des cartes exponentielles (celles pour lesquelles 𝐞<2π{\parallel \mathbf{e} \parallel} < 2\pi ) et d’établir une correspondance biunivoque avec les matrices de rotation. C’est l’essence du théorème de rotation d’Euler.

Considérons maintenant la concaténation de plusieurs rotations. Disons que 𝐞1\mathbf{e}_{1} et 𝐞2\mathbf{e}_{2} sont deux rotations en format carte exponentielle. Le résultat de l’exécution des rotations en séquence, par exemple 𝐞1\mathbf{e}_{1} puis 𝐞2\mathbf{e}_{2} , n’est pas le même que l’exécution d’une rotation unique 𝐞1+𝐞2\mathbf{e}_{1} + \mathbf{e}_{2} . Nous savons que cela ne peut pas être vrai, parce que l’addition vectorielle ordinaire est commutative, mais les rotations dans l’espace à trois dimensions ne le sont pas. Supposons que 𝐞1=[90o,0,0]\mathbf{e}_{1} = \lbrack 90^{o},0,0\rbrack et 𝐞2=[0,90o,0]\mathbf{e}_{2} = \lbrack 0,90^{o},0\rbrack . Avec nos conventions, c’est une rotation de tangage vers le bas de 90o90^{o} et une rotation de cap de 90o90^{o} vers l’est. En effectuant 𝐞1\mathbf{e}_{1} suivi de 𝐞2\mathbf{e}_{2} , nous finirions par regarder vers le bas avec notre tête pointant vers l’est, mais en faisant les choses dans l’ordre inverse, nous finissons « sur l’oreille » face à l’est. Mais que se passerait-il si les angles étaient beaucoup plus petits, disons 2o2^{o} au lieu de 90o90^{o} ? Maintenant, les rotations finales sont plus similaires. À mesure que nous réduisons la magnitude des angles de rotation, l’importance de l’ordre diminue, et à l’extrême, pour des rotations « infinitésimales », l’ordre est complètement sans importance. En d’autres termes, pour des rotations infinitésimales, les cartes exponentielles peuvent être additionnées vectoriellement. Les infinitésimaux sont des sujets importants du calcul, et ils sont au cœur de la définition du taux de changement. Nous examinons ces sujets dans le chapitre 11, mais pour l’instant, l’idée de base est que les cartes exponentielles ne s’additionnent pas vectoriellement lorsqu’elles sont utilisées pour définir une quantité de rotation (un déplacement angulaire ou une orientation), mais elles s’additionnent correctement vectoriellement lorsqu’elles décrivent un taux de rotation. C’est pourquoi les cartes exponentielles sont parfaitement adaptées pour décrire la vitesse angulaire.

Avant de quitter ce sujet, un regrettable avertissement concernant la terminologie. Des noms alternatifs pour ces deux concepts simples abondent. Nous avons essayé de choisir les noms les plus standard possible, mais il était difficile de trouver un fort consensus. Certains auteurs utilisent le terme « axe-angle » pour décrire les deux méthodes (étroitement liées) sans vraiment les distinguer. Encore plus déroutant est l’utilisation du terme « axe d’Euler » pour se référer à l’une ou l’autre forme (mais pas aux angles d’Euler !). « Vecteur de rotation » est un autre terme que vous pourriez voir attaché à ce que nous appelons carte exponentielle. Enfin, le terme « carte exponentielle », dans le contexte plus large de l’algèbre de Lie d’où provient le terme, fait en réalité référence à une opération (une « carte ») plutôt qu’à une quantité. Nous nous excusons de la confusion, mais ce n’est pas notre faute.

8.5Quaternions

Le terme quaternion est un peu un mot à la mode en mathématiques 3D. Les quaternions portent une certaine mystique — ce qui est une façon euphémique de dire que beaucoup de gens trouvent les quaternions compliqués et confus. Nous pensons que la façon dont les quaternions sont présentés dans la plupart des textes contribue à leur confusion, et nous espérons que notre approche légèrement différente aidera à dissiper la « mystique » des quaternions.

Il y a une raison mathématique pour laquelle l’utilisation de seulement trois nombres pour représenter une orientation 3D est garantie de causer les problèmes que nous avons discutés avec les angles d’Euler, comme le blocage de cardan. Cela a quelque chose à voir avec des termes mathématiques assez avancés9 tels que « variétés ». Un quaternion évite ces problèmes en utilisant quatre nombres pour exprimer une orientation (d’où le nom quaternion).

Cette section décrit comment utiliser un quaternion pour définir un déplacement angulaire. Nous allons nous écarter quelque peu de la présentation traditionnelle, qui met l’accent sur l’interprétation intéressante (mais, à notre avis, non essentielle) des quaternions comme nombres complexes. Au lieu de cela, nous allons développer les quaternions principalement d’une perspective géométrique. Voici ce qui nous attend : Premièrement, la section 8.5.1 introduit quelques notations de base. La section 8.5.2 est probablement la section la plus importante — elle explique comment un quaternion peut être interprété géométriquement. Les sections 8.5.3 à 8.5.11 passent en revue les propriétés et opérations de base des quaternions, en examinant chacune d’une perspective géométrique. La section 8.5.12 aborde l’opération importante slerp, utilisée pour interpoler entre deux quaternions et constituant l’un des principaux avantages des quaternions. La section 8.5.13 aborde les avantages et les inconvénients des quaternions. La section 8.5.14 est une digression facultative sur la façon dont les quaternions peuvent être interprétés comme des nombres complexes 4D. La section 8.5.15 résume les propriétés des quaternions.

Ne soyez pas effrayé par ce qui semble être beaucoup de mathématiques difficiles dans cette section. Les choses les plus importantes à retenir sur les quaternions sont les concepts de haut niveau résumés dans la section 8.5.15. Les détails concrets des quaternions sont donnés ici pour montrer que tout ce qui concerne les quaternions peut être dérivé, et vous n’avez pas à nous faire confiance sur parole. Une compréhension détaillée des quaternions n’est pas vraiment nécessaire pour les utiliser,9 mais vous devez comprendre ce que les quaternions peuvent faire.

8.5.1Notation des quaternions

Un quaternion contient une composante scalaire et une composante vectorielle 3D. Nous appelons généralement la composante scalaire ww . Nous pouvons désigner la composante vectorielle comme une entité unique 𝐯\mathbf{v} ou comme des composantes individuelles xx , yy et zz . Voici des exemples des deux notations :

Deux types de notation de quaternion

[w𝐯],[w(xyz)].\begin{bmatrix} w & \mathbf{v} \\ \end{bmatrix},\begin{bmatrix} w & \begin{pmatrix} x & y & z \\ \end{pmatrix} \\ \end{bmatrix}.

Dans certains cas, il sera pratique d’utiliser la notation plus courte avec 𝐯\mathbf{v} , et dans d’autres cas, la version « développée » est plus claire. Ce chapitre présente la plupart des équations dans les deux formes.

Nous pouvons également écrire les quaternions développés verticalement :

[w(xyz)].\begin{bmatrix} w \\ \begin{pmatrix} x \\ y \\ z \\ \end{pmatrix} \\ \end{bmatrix}.

Contrairement aux vecteurs ordinaires, il n’y a pas de distinction significative entre quaternions « ligne » et « colonne ». Nous sommes libres de faire le choix strictement pour des raisons esthétiques.

Nous désignons les variables de quaternion avec les mêmes conventions de typographie utilisées pour les vecteurs : lettres minuscules en gras (par exemple, 𝐪\mathbf{q}). Lorsque des vecteurs et des quaternions apparaissent ensemble, le contexte (et les lettres choisies pour les variables !) rend généralement clair lesquels sont lesquels.

8.5.2Que signifient ces quatre nombres ?

La forme quaternion est étroitement liée aux formes axe-angle et carte exponentielle de la section 8.4. Rappelons brièvement la notation de cette section, qui sera également utilisée ici. Le vecteur unitaire 𝐧̂\hat{\mathbf{n}} définit un axe de rotation, et le scalaire θ\theta est la quantité de rotation autour de cet axe. Ainsi, la paire (θ,𝐧̂)(\theta,\hat{\mathbf{n}}) définit un déplacement angulaire à l’aide du système axe-angle. Vous avez besoin d’une main gauche ou droite11 pour déterminer quelle direction est la rotation positive.

Un quaternion contient également un axe et un angle, mais 𝐧̂\hat{\mathbf{n}} et θ\theta ne sont pas simplement stockés directement dans les quatre nombres du quaternion, comme c’est le cas dans l’axe-angle (ce serait trop facile !). À la place, ils sont encodés d’une façon qui peut sembler étrange au premier abord, mais qui s’avère très pratique. L’équation (8.2) montre comment les valeurs d’un quaternion sont liées à θ\theta et 𝐧̂\hat{\mathbf{n}} , en utilisant les deux formes de notation de quaternion :

Signification géométrique des quatre valeurs d’un quaternion

[w𝐯]=[cos(θ/2)sin(θ/2)𝐧̂],[w(xyz)]=[cos(θ/2)(sin(θ/2)nxsin(θ/2)nysin(θ/2)nz)].\begin{matrix} \begin{bmatrix} w & \mathbf{v} \\ \end{bmatrix} & {= \begin{bmatrix} {\cos(\theta/2)} & {\sin(\theta/2)\hat{\mathbf{n}}} \\ \end{bmatrix},} \\ \begin{bmatrix} w & \begin{pmatrix} x & y & z \\ \end{pmatrix} \\ \end{bmatrix} & {= \begin{bmatrix} {\cos(\theta/2)} & \begin{pmatrix} {\sin(\theta/2)n_{x}} & {\sin(\theta/2)n_{y}} & {\sin(\theta/2)n_{z}} \\ \end{pmatrix} \\ \end{bmatrix}.} \\ \end{matrix}

Gardez à l’esprit que ww est lié à θ\theta , mais qu’ils ne sont pas identiques. De même, 𝐯\mathbf{v} et 𝐧̂\hat{\mathbf{n}} sont liés, mais pas identiques.

Les sections suivantes discutent d’un certain nombre d’opérations sur les quaternions d’un point de vue mathématique et géométrique.

8.5.3Négation d’un quaternion

Les quaternions peuvent être négativés. Cela se fait de façon évidente en négativant chaque composante :

Négation d’un quaternion

𝐪=[w(xyz)]=[w(xyz)]=[w𝐯]=[w𝐯].\begin{matrix} \begin{matrix} {- \mathbf{q}} & {= - \begin{bmatrix} w & \begin{pmatrix} x & y & z \\ \end{pmatrix} \\ \end{bmatrix} = \begin{bmatrix} {- w} & \begin{pmatrix} {- x} & {- y} & {- z} \\ \end{pmatrix} \\ \end{bmatrix}} \\ & {= - \begin{bmatrix} w & \mathbf{v} \\ \end{bmatrix} = \begin{bmatrix} {- w} & {- \mathbf{v}} \\ \end{bmatrix}.} \\ \end{matrix} \\ \end{matrix}

Le fait surprenant concernant la négation d’un quaternion est qu’elle ne fait vraiment rien, du moins dans le contexte du déplacement angulaire.

Les quaternions 𝐪\mathbf{q} et 𝐪- \mathbf{q} décrivent le même déplacement angulaire. Tout déplacement angulaire en 3D a exactement deux représentations distinctes en format quaternion, et elles sont négatives l’une de l’autre.

Il n’est pas trop difficile de voir pourquoi c’est vrai. Si nous ajoutons 360o360^{o} à θ\theta , cela ne change pas le déplacement angulaire représenté par 𝐪\mathbf{q} , mais cela négative les quatre composantes de 𝐪\mathbf{q} .

8.5.4Quaternion(s) identité

Géométriquement, il existe deux quaternions « identité » représentant « aucun déplacement angulaire ». Ce sont :

Quaternions identité

[10]et[10].\begin{bmatrix} 1 & 0 \\ \end{bmatrix}\text{et}\begin{bmatrix} {- 1} & 0 \\ \end{bmatrix}.

(Notez le zéro en gras, qui indique le vecteur zéro.) Lorsque θ\theta est un multiple pair de 360°, alors cos(θ/2)=1\cos(\theta/2) = 1 , et nous avons la première forme. Si θ\theta est un multiple impair de 360°, alors cos(θ/2)=1\cos(\theta/2) = - 1 , et nous avons la deuxième forme. Dans les deux cas, sin(θ/2)\sin(\theta/2) = 0, donc la valeur de 𝐧̂\hat{\mathbf{n}} est sans importance. Cela a un sens intuitif ; si l’angle de rotation θ\theta est un nombre entier de révolutions complètes autour de n’importe quel axe, alors aucun changement réel n’est apporté à l’orientation.

Algébriquement, il n’y a vraiment qu’un seul quaternion identité : [1,0]\lbrack 1,0\rbrack . Lorsque nous multiplions un quaternion 𝐪\mathbf{q} quelconque par le quaternion identité, le résultat est 𝐪\mathbf{q} . (Nous présentons la multiplication des quaternions dans la section 8.5.7.) Lorsque nous multiplions un quaternion 𝐪\mathbf{q} par l’autre quaternion « identité géométrique » [1,0]\lbrack - 1,0\rbrack , nous obtenons 𝐪- \mathbf{q} . Géométriquement, cela donne le même quaternion, puisque 𝐪\mathbf{q} et 𝐪- \mathbf{q} représentent le même déplacement angulaire. Mathématiquement, cependant, 𝐪\mathbf{q} et 𝐪- \mathbf{q} ne sont pas égaux, donc [1,0]\lbrack - 1,0\rbrack n’est pas un « vrai » quaternion identité.

8.5.5Norme d’un quaternion

Nous pouvons calculer la norme d’un quaternion, tout comme nous pouvons le faire pour les vecteurs et les nombres complexes. La notation et la formule présentées dans l’équation (8.4) sont similaires à celles utilisées pour les vecteurs :

Norme d’un quaternion

𝐪=[w(xyz)]=w2+x2+y2+z2=[w𝐯]=w2+𝐯2.\begin{matrix} \begin{matrix} {\parallel \mathbf{q} \parallel} & {= {\parallel \begin{bmatrix} w & \begin{pmatrix} x & y & z \\ \end{pmatrix} \\ \end{bmatrix} \parallel} = \sqrt{w^{2} + x^{2} + y^{2} + z^{2}}} \\ & {= {\parallel \begin{bmatrix} w & \mathbf{v} \\ \end{bmatrix} \parallel} = \sqrt{w^{2} + {\parallel \mathbf{v} \parallel}^{2}}.} \\ \end{matrix} \\ \end{matrix}

Voyons ce que cela signifie géométriquement pour un quaternion de rotation :

Les quaternions de rotation ont une norme unitaire

𝐪=[w𝐯]=w2+𝐯2=cos2(θ/2)+(sin(θ/2)𝐧̂)2(substitution avec θ et 𝐧̂)=cos2(θ/2)+sin2(θ/2)𝐧̂2=cos2(θ/2)+sin2(θ/2)(1)(𝐧̂ est un vecteur unitaire)=1(sin2x+cos2x=1)=1.\begin{matrix} {\parallel \mathbf{q} \parallel} & {= {\parallel \begin{bmatrix} w & \mathbf{v} \\ \end{bmatrix} \parallel} = \sqrt{w^{2} + {\parallel \mathbf{v} \parallel}^{2}}} & & \\ & {= \sqrt{\cos^{2}(\theta/2) + \left( \sin(\theta/2){\parallel \hat{\mathbf{n}} \parallel} \right)^{2}}} & & {\text{(substitution\ avec\ }\theta\text{\ et\ }\hat{\mathbf{n}}\text{)}} \\ & {= \sqrt{\cos^{2}(\theta/2) + \sin^{2}(\theta/2){\parallel \hat{\mathbf{n}} \parallel}^{2}}} & & \\ & {= \sqrt{\cos^{2}(\theta/2) + \sin^{2}(\theta/2)(1)}} & & {\text{(}\hat{\mathbf{n}}\text{\ est\ un\ vecteur\ unitaire)}} \\ & {= \sqrt{1}} & & {(\sin^{2}x + \cos^{2}x = 1)} \\ & {= 1.} & & \\ \end{matrix}

C’est une observation importante.

Pour nos besoins d’utilisation des quaternions pour représenter l’orientation, tous les quaternions sont des quaternions unitaires, ayant une norme égale à l’unité.

Pour des informations concernant les quaternions non normalisés, voir le rapport technique de Dam et al. [2].

8.5.6Conjugué et inverse d’un quaternion

Le conjugué d’un quaternion, noté 𝐪*\mathbf{q}^{\ast} , est obtenu en négativant la partie vectorielle du quaternion :

Conjugué d’un quaternion

𝐪*=[w𝐯]*=[w𝐯]=[w(xyz)]*=[w(xyz)].\begin{matrix} \mathbf{q}^{\ast} & {= \begin{bmatrix} w & \mathbf{v} \\ \end{bmatrix}^{\ast} = \begin{bmatrix} w & {- \mathbf{v}} \\ \end{bmatrix}} \\ & {= \begin{bmatrix} w & \begin{pmatrix} x & y & z \\ \end{pmatrix} \\ \end{bmatrix}^{\ast} = \begin{bmatrix} w & \begin{pmatrix} {- x} & {- y} & {- z} \\ \end{pmatrix} \\ \end{bmatrix}.} \\ \end{matrix}

Le terme « conjugué » est hérité de l’interprétation d’un quaternion comme nombre complexe. Nous examinons cette interprétation plus en détail dans la section 8.5.14.

L’inverse d’un quaternion, noté 𝐪1\mathbf{q}^{- 1} , est défini comme le conjugué d’un quaternion divisé par sa norme :

Inverse d’un quaternion

𝐪1=𝐪*𝐪.\begin{matrix} {\mathbf{q}^{- 1} = \frac{\mathbf{q}^{\ast}}{\parallel \mathbf{q} \parallel}.} \\ \end{matrix}

L’inverse du quaternion présente une correspondance intéressante avec l’inverse multiplicatif pour les nombres réels (scalaires). Pour les nombres réels, l’inverse multiplicatif a1a^{- 1} est 1/a1/a . En d’autres termes, a(a1)=a1a=1a(a^{- 1}) = a^{- 1}a = 1 . Il en va de même pour les quaternions. Lorsque nous multiplions un quaternion 𝐪\mathbf{q} par son inverse 𝐪1\mathbf{q}^{- 1} , nous obtenons le quaternion identité [1,0]\lbrack 1,0\rbrack . (Nous abordons la multiplication des quaternions dans la section 8.5.7.)

L’équation (8.6) est la définition officielle de l’inverse d’un quaternion. Cependant, si vous n’êtes intéressé que par les quaternions représentant des rotations pures, comme c’est le cas dans ce livre, tous les quaternions sont des quaternions unitaires et le conjugué et l’inverse sont équivalents.

Le conjugué (inverse) est intéressant parce que 𝐪\mathbf{q} et 𝐪*\mathbf{q}^{\ast} représentent des déplacements angulaires opposés. Il est facile de comprendre pourquoi. En négativant 𝐯\mathbf{v} , nous négativons l’axe de rotation 𝐧̂\hat{\mathbf{n}} . Cela ne change pas l’axe dans le sens physique, puisque 𝐧̂\hat{\mathbf{n}} et 𝐧̂- \hat{\mathbf{n}} sont parallèles. Cependant, cela inverse la direction que nous considérons comme rotation positive. Ainsi, 𝐪\mathbf{q} tourne autour d’un axe d’un montant θ\theta , et 𝐪*\mathbf{q}^{\ast} tourne dans la direction opposée du même montant.

Pour nos besoins, une définition alternative du conjugué de quaternion aurait pu être de négativer ww en laissant 𝐯\mathbf{v} (et donc 𝐧̂\hat{\mathbf{n}}) inchangé. Cela aurait négativé la quantité de rotation θ\theta , plutôt que d’inverser ce qui est considéré comme rotation positive en retournant l’axe de rotation. Cela aurait été équivalent à la définition donnée dans l’équation (8.5) (pour nos besoins géométriques, du moins) et aurait fourni une interprétation géométrique légèrement plus intuitive. Cependant, le terme conjugué a une signification particulière dans le contexte des nombres complexes, donc restons avec la définition originale.

8.5.7Multiplication des quaternions

Les quaternions peuvent être multipliés. Le résultat est similaire au produit vectoriel pour les vecteurs, en ce qu’il produit un autre quaternion (pas un scalaire), et il n’est pas commutatif. Cependant, la notation est différente : nous notons la multiplication des quaternions simplement en plaçant les deux opérandes côte à côte. La formule pour la multiplication des quaternions peut être facilement dérivée à partir de la définition des quaternions comme nombres complexes (voir l’exercice 6), mais nous la présentons ici sans développement, en utilisant les deux notations de quaternion :

Produit de quaternions

𝐪1𝐪2=[w1(x1y1z1)][w2(x2y2z2)]=[w1w2x1x2y1y2z1z2(w1x2+x1w2+y1z2z1y2w1y2+y1w2+z1x2x1z2w1z2+z1w2+x1y2y1x2)]=[w1𝐯1][w2𝐯2]=[w1w2𝐯1𝐯2w1𝐯2+w2𝐯1+𝐯1×𝐯2].\begin{matrix} {\mathbf{q}_{1}\mathbf{q}_{2}} & {= \begin{bmatrix} w_{1} & \begin{pmatrix} x_{1} & y_{1} & z_{1} \\ \end{pmatrix} \\ \end{bmatrix}\begin{bmatrix} w_{2} & \begin{pmatrix} x_{2} & y_{2} & z_{2} \\ \end{pmatrix} \\ \end{bmatrix}} \\ & {= \begin{bmatrix} {w_{1}w_{2} - x_{1}x_{2} - y_{1}y_{2} - z_{1}z_{2}} \\ \begin{pmatrix} {w_{1}x_{2} + x_{1}w_{2} + y_{1}z_{2} - z_{1}y_{2}} \\ {w_{1}y_{2} + y_{1}w_{2} + z_{1}x_{2} - x_{1}z_{2}} \\ {w_{1}z_{2} + z_{1}w_{2} + x_{1}y_{2} - y_{1}x_{2}} \\ \end{pmatrix} \\ \end{bmatrix}} \\ & {= \begin{bmatrix} w_{1} & \mathbf{v}_{1} \\ \end{bmatrix}\begin{bmatrix} w_{2} & \mathbf{v}_{2} \\ \end{bmatrix}} \\ & {= \begin{bmatrix} {w_{1}w_{2} - \mathbf{v}_{1} \cdot \mathbf{v}_{2}} & {w_{1}\mathbf{v}_{2} + w_{2}\mathbf{v}_{1} + \mathbf{v}_{1} \times \mathbf{v}_{2}} \\ \end{bmatrix}.} \\ \end{matrix}

Le produit de quaternions est également connu sous le nom de produit de Hamilton ; vous comprendrez pourquoi après avoir lu l’histoire des quaternions dans la section 8.5.14.

Mentionnons rapidement trois propriétés de la multiplication des quaternions, qui peuvent toutes être facilement démontrées en utilisant la définition donnée ci-dessus. Premièrement, la multiplication des quaternions est associative, mais pas commutative :

La multiplication des quaternions est associative, mais pas commutative

(𝐚𝐛)𝐜=𝐚(𝐛𝐜),𝐚𝐛𝐛𝐚.\begin{matrix} {(\mathbf{a}\mathbf{b})\mathbf{c}} & {= \mathbf{a}(\mathbf{b}\mathbf{c}),} \\ {\mathbf{a}\mathbf{b}} & {\neq \mathbf{b}\mathbf{a}.} \\ \end{matrix}

Deuxièmement, la norme d’un produit de quaternions est égale au produit des normes (voir l’exercice 9) :

Norme du produit de quaternions

𝐪1𝐪2=𝐪1𝐪2.{\parallel {\mathbf{q}_{1}\mathbf{q}_{2}} \parallel} = {\parallel \mathbf{q}_{1} \parallel}{\parallel \mathbf{q}_{2} \parallel}.

C’est très significatif car cela nous garantit que lorsque nous multiplions deux quaternions unitaires, le résultat est un quaternion unitaire.

Enfin, l’inverse d’un produit de quaternions est égal au produit des inverses pris dans l’ordre inverse :

Inverse du produit de quaternions

(𝐚𝐛)1=𝐛1𝐚1,(𝐪1𝐪2𝐪n1𝐪n)1=𝐪n1𝐪n11𝐪21𝐪11.\begin{matrix} {(\mathbf{a}\mathbf{b})^{- 1}} & {= \mathbf{b}^{- 1}\mathbf{a}^{- 1},} \\ {(\mathbf{q}_{1}\mathbf{q}_{2}\cdots\mathbf{q}_{n - 1}\mathbf{q}_{n})^{- 1}} & {= {\mathbf{q}_{n}}^{- 1}{\mathbf{q}_{n - 1}}^{- 1}\cdots{\mathbf{q}_{2}}^{- 1}{\mathbf{q}_{1}}^{- 1}.} \\ \end{matrix}

Maintenant que nous connaissons quelques propriétés de base de la multiplication des quaternions, parlons de pourquoi l’opération est réellement utile. « Étendons » un point 3D standard (x,y,z)(x,y,z) dans l’espace des quaternions en définissant le quaternion 𝐩=[0,(x,y,z)]\mathbf{p} = \lbrack 0,(x,y,z)\rbrack . En général, 𝐩\mathbf{p} n’est pas un quaternion de rotation valide, car il peut avoir une norme quelconque. Soit 𝐪\mathbf{q} un quaternion de rotation dans la forme que nous avons discutée, [cosθ/2,𝐧̂sinθ/2]\lbrack\cos\theta/2,\hat{\mathbf{n}}\sin\theta/2\rbrack , où 𝐧̂\hat{\mathbf{n}} est un vecteur unitaire axe de rotation, et θ\theta est l’angle de rotation. Il est surprenant de réaliser que nous pouvons faire pivoter le point 3D 𝐩\mathbf{p} autour de 𝐧̂\hat{\mathbf{n}} en effectuant la multiplication de quaternions plutôt curieuse

Utilisation de la multiplication de quaternions pour faire pivoter un vecteur 3D

𝐩=𝐪𝐩𝐪1.\begin{matrix} {\mathbf{p}^{\prime} = \mathbf{q}\mathbf{p}\mathbf{q}^{- 1}.} \\ \end{matrix}

Nous pourrions prouver cela en développant la multiplication, en substituant 𝐧̂\hat{\mathbf{n}} et θ\theta , et en comparant le résultat à la matrice que nous avons dérivée pour faire pivoter autour d’un axe arbitraire (équation (5.1.3)), et c’est effectivement l’approche adoptée dans la plupart des textes sur les quaternions. Bien que cela soit certainement un moyen efficace de vérifier que l’astuce fonctionne, cela nous laisse à nous demander comment quelqu’un aurait pu tomber dessus en premier lieu. Dans la section 8.7.3, nous dérivons la conversion du quaternion en forme matricielle d’une façon directe, uniquement à partir de la géométrie des rotations et sans faire référence à 𝐪𝐩𝐪1\mathbf{q}\mathbf{p}\mathbf{q}^{- 1} . Quant à la façon dont l’association a été découverte, nous ne pouvons pas le dire avec certitude, mais nous offrirons une ligne de pensée pouvant conduire une personne à découvrir la connexion entre ce produit étrange et les rotations dans la section 8.5.14. Cette discussion explique également comment quelqu’un aurait pu découvrir qu’il serait fructueux d’utiliser la moitié de l’angle de rotation pour les composantes.

Il s’avère que la correspondance entre la multiplication des quaternions et les rotations de vecteurs 3D est davantage d’un intérêt théorique que pratique. Certaines personnes (« quaternionphiles » ?) aiment attribuer aux quaternions la propriété utile selon laquelle les rotations de vecteurs sont immédiatement accessibles en utilisant l’équation (8.7). Aux amoureux des quaternions, nous admettons que cette notation compacte est un avantage d’une certaine façon, mais son avantage pratique dans les calculs est discutable. Si vous effectuez réellement ces calculs, vous constaterez que le nombre d’opérations est à peu près le même que la conversion du quaternion en matrice de rotation équivalente (en utilisant l’équation (8.20), développée dans la section 8.7.3) puis la multiplication du vecteur par cette matrice. Pour cette raison, nous ne considérons pas que les quaternions possèdent une capacité directe à faire pivoter des vecteurs, du moins pour les besoins pratiques dans un ordinateur.

Bien que la correspondance entre 𝐪𝐩𝐪1\mathbf{q}\mathbf{p}\mathbf{q}^{- 1} et la rotation ne soit pas d’une importance pratique directe, elle est d’une importance théorique suprême. Elle nous conduit à une utilisation légèrement différente de la multiplication des quaternions, et cette utilisation est très pratique en programmation. Examinons ce qui se passe lorsque plusieurs rotations sont appliquées à un vecteur. Nous ferons pivoter le vecteur 𝐩\mathbf{p} par le quaternion 𝐚\mathbf{a} , puis nous ferons pivoter ce résultat par un autre quaternion 𝐛\mathbf{b} :

Concaténation de plusieurs rotations avec l’algèbre des quaternions

𝐩=𝐛(𝐚𝐩𝐚1)𝐛1=(𝐛𝐚)𝐩(𝐚1𝐛1)=(𝐛𝐚)𝐩(𝐛𝐚)1.\begin{matrix} \mathbf{p}^{\prime} & {= \mathbf{b}(\mathbf{a}\mathbf{p}\mathbf{a}^{- 1})\mathbf{b}^{- 1}} \\ & {= (\mathbf{b}\mathbf{a})\mathbf{p}(\mathbf{a}^{- 1}\mathbf{b}^{- 1})} \\ & {= (\mathbf{b}\mathbf{a})\mathbf{p}(\mathbf{b}\mathbf{a})^{- 1}.} \\ \end{matrix}

Remarquez que faire pivoter par 𝐚\mathbf{a} puis par 𝐛\mathbf{b} est équivalent à effectuer une seule rotation par le produit de quaternions 𝐛𝐚\mathbf{b}\mathbf{a} . C’est une observation clé.

La multiplication des quaternions peut être utilisée pour concaténer plusieurs rotations, tout comme la multiplication matricielle.

Nous disons « tout comme la multiplication matricielle », mais en fait il y a une différence légèrement irritante. Avec la multiplication matricielle, notre préférence d’utiliser des vecteurs ligne place les vecteurs à gauche, ce qui donne la belle propriété que les rotations concaténées se lisent de gauche à droite dans l’ordre de transformation. Avec les quaternions, nous n’avons pas cette flexibilité : la concaténation de plusieurs rotations se lira toujours « de l’intérieur vers l’extérieur » de droite à gauche.12

8.5.8« Différence » de quaternions

En utilisant la multiplication et l’inverse des quaternions, nous pouvons calculer la différence entre deux quaternions, « différence » signifiant le déplacement angulaire d’une orientation à une autre. En d’autres termes, étant donné les orientations 𝐚\mathbf{a} et 𝐛\mathbf{b} , nous pouvons calculer le déplacement angulaire 𝐝\mathbf{d} qui tourne de 𝐚\mathbf{a} vers 𝐛\mathbf{b} . Cela peut être exprimé de façon compacte comme

𝐝𝐚=𝐛.\mathbf{d}\mathbf{a} = \mathbf{b}.

(Rappelons que la multiplication des quaternions effectue les rotations de droite à gauche.)

Résolvons pour 𝐝\mathbf{d} . Si les variables dans l’équation représentaient des scalaires, nous pourrions simplement diviser par 𝐚\mathbf{a} . Cependant, représentaient des scalaires, nous pourrions simplement diviser par 𝐚\mathbf{a} . Cependant, nous ne pouvons pas diviser les quaternions ; nous pouvons seulement les multiplier. Peut-être que la multiplication par l’inverse produira l’effet désiré ? En multipliant les deux membres par 𝐚1\mathbf{a}^{- 1} à droite (nous devons faire attention car la multiplication des quaternions n’est pas commutative), nous obtenons

La « différence » de quaternions

(𝐝𝐚)𝐚1=𝐛𝐚1,𝐝(𝐚𝐚1)=𝐛𝐚1,𝐝[10]=𝐛𝐚1,𝐝=𝐛𝐚1.\begin{matrix} {(\mathbf{d}\mathbf{a})\mathbf{a}^{- 1}} & {= \mathbf{b}\mathbf{a}^{- 1},} \\ {\mathbf{d}(\mathbf{a}\mathbf{a}^{- 1})} & {= \mathbf{b}\mathbf{a}^{- 1},} \\ {\mathbf{d}\,\begin{bmatrix} 1 & 0 \\ \end{bmatrix}} & {= \mathbf{b}\mathbf{a}^{- 1},} \\ \mathbf{d} & {= \mathbf{b}\mathbf{a}^{- 1}.} \\ \end{matrix}

Nous avons maintenant un moyen de générer un quaternion représentant le déplacement angulaire d’une orientation à une autre. Nous l’utilisons à la Section 8.5.12, lorsque nous explorons le slerp.

Mathématiquement, la différence angulaire entre deux quaternions est en réalité plus similaire à une division qu’à une vraie différence (soustraction).

8.5.9Produit scalaire de quaternions

L’opération de produit scalaire est définie pour les quaternions. La notation et la définition de cette opération sont très similaires au produit scalaire de vecteurs :

Produit scalaire de quaternions

𝐪1𝐪2=[w1𝐯1][w2𝐯2]=w1w2+𝐯1𝐯2=[w1(x1y1z1)][w2(x2y2z2)]=w1w2+x1x2+y1y2+z1z2.\begin{matrix} \begin{matrix} {\mathbf{q}_{1} \cdot \mathbf{q}_{2}} & {= \begin{bmatrix} w_{1} & \mathbf{v}_{1} \\ \end{bmatrix} \cdot \begin{bmatrix} w_{2} & \mathbf{v}_{2} \\ \end{bmatrix}} \\ & {= w_{1}w_{2} + \mathbf{v}_{1} \cdot \mathbf{v}_{2}} \\ & {= \begin{bmatrix} w_{1} & \begin{pmatrix} x_{1} & y_{1} & z_{1} \\ \end{pmatrix} \\ \end{bmatrix} \cdot \begin{bmatrix} w_{2} & \begin{pmatrix} x_{2} & y_{2} & z_{2} \\ \end{pmatrix} \\ \end{bmatrix}} \\ & {= w_{1}w_{2} + x_{1}x_{2} + y_{1}y_{2} + z_{1}z_{2}.} \\ \end{matrix} \\ \end{matrix}

Comme le produit scalaire de vecteurs, le résultat est un scalaire. Pour des quaternions unitaires 𝐚\mathbf{a} et 𝐛\mathbf{b} , 1𝐚𝐛1- 1 \leq \mathbf{a} \cdot \mathbf{b} \leq 1 .

Le produit scalaire n’est peut-être pas l’un des opérateurs quaternioniques les plus fréquemment utilisés, du moins en programmation de jeux vidéo, mais il a une interprétation géométrique intéressante. À la Section 8.5.8, nous avons considéré le quaternion différence 𝐝=𝐛𝐚*\mathbf{d} = \mathbf{b}\mathbf{a}^{\ast} , qui décrit le déplacement angulaire de l’orientation 𝐚\mathbf{a} vers l’orientation 𝐛\mathbf{b} . (Nous supposons des quaternions unitaires et remplaçons l’inverse du quaternion par le conjugué.) Si nous développons le produit et examinons le contenu de 𝐝\mathbf{d} , nous trouvons que la composante ww est égale au produit scalaire 𝐚𝐛\mathbf{a} \cdot \mathbf{b} !

Qu’est-ce que cela signifie géométriquement ? Rappelons le théorème de rotation d’Euler : nous pouvons passer de l’orientation 𝐚\mathbf{a} à l’orientation 𝐛\mathbf{b} par une seule rotation autour d’un axe soigneusement choisi. Cet axe et cet angle, uniquement déterminés (à un renversement de signe près), sont précisément ceux encodés dans 𝐝\mathbf{d} . En nous rappelant la relation entre la composante ww et l’angle de rotation θ\theta , nous voyons que 𝐚𝐛=cos(θ/2)\mathbf{a} \cdot \mathbf{b} = \cos(\theta/2) , où θ\theta est la quantité de rotation nécessaire pour aller de l’orientation 𝐚\mathbf{a} à l’orientation 𝐛\mathbf{b} .

En résumé, le produit scalaire de quaternions a une interprétation similaire à celle du produit scalaire de vecteurs. Plus la valeur absolue du produit scalaire de quaternions 𝐚𝐛\mathbf{a} \cdot \mathbf{b} est grande, plus les déplacements angulaires représentés par 𝐚\mathbf{a} et 𝐛\mathbf{b} sont « similaires ». Tandis que le produit scalaire de vecteurs donne le cosinus de l’angle entre les vecteurs, le produit scalaire de quaternions donne le cosinus de la moitié de l’angle nécessaire pour faire tourner un quaternion vers l’autre. Pour mesurer la similarité, nous nous intéressons généralement seulement à la valeur absolue de 𝐚𝐛\mathbf{a} \cdot \mathbf{b} , car 𝐚𝐛=(𝐚𝐛)\mathbf{a} \cdot \mathbf{b} = - (\mathbf{a} \cdot - \mathbf{b}) , même si 𝐛\mathbf{b} et 𝐛- \mathbf{b} représentent le même déplacement angulaire.

Bien que l’utilisation directe du produit scalaire soit peu fréquente dans la plupart des codes de jeux vidéo, le produit scalaire est la première étape du calcul de la fonction slerp, dont nous parlons à la Section 8.5.12.

8.5.10Logarithme, exponentielle et multiplication par un scalaire de quaternions

Cette section traite de trois opérations sur les quaternions qui, bien qu’elles soient rarement utilisées directement, constituent la base de plusieurs opérations quaternioniques importantes. Ces opérations sont le logarithme de quaternion, l’exponentielle, et la multiplication par un scalaire.

Commençons par reformuler notre définition d’un quaternion en introduisant une variable α\alpha égale au demi-angle, θ/2\theta/2 :

Définition d’un quaternion en termes du demi-angle 𝛂\mathbf{\alpha}

α=θ/2,𝐪=[cosα𝐧̂sinα].\begin{matrix} \alpha & {= \theta/2,} & \mathbf{q} & {= \begin{bmatrix} {\cos\alpha} & {\hat{\mathbf{n}}\sin\alpha} \\ \end{bmatrix}.} \\ \end{matrix}

Le logarithme de 𝐪\mathbf{q} est défini comme suit

Le logarithme d’un quaternion

log𝐪=log([cosα𝐧̂sinα])[0α𝐧̂].\begin{matrix} {\log\mathbf{q}} & {= \log\left( \begin{bmatrix} {\cos\alpha} & {\hat{\mathbf{n}}\sin\alpha} \\ \end{bmatrix} \right) \equiv \begin{bmatrix} 0 & {\alpha\hat{\mathbf{n}}} \\ \end{bmatrix}.} \\ \end{matrix}

Nous utilisons la notation \equiv pour signifier « égal par définition ». En général, log𝐪\log\mathbf{q} n’est pas un quaternion unitaire. Notez la similitude entre le calcul du logarithme d’un quaternion et le format de la carte exponentielle (voir Section 8.4).

La fonction exponentielle est définie de manière exactement inverse. Nous définissons d’abord le quaternion 𝐩\mathbf{p} de la forme [0,α𝐧̂]\lbrack 0,\alpha\hat{\mathbf{n}}\rbrack , avec 𝐧̂\hat{\mathbf{n}} un vecteur unitaire :

𝐩=[0α𝐧̂],(𝐧̂=1).\begin{matrix} \mathbf{p} & {= \begin{bmatrix} 0 & {\alpha\hat{\mathbf{n}}} \\ \end{bmatrix},} & & {({\parallel \hat{\mathbf{n}} \parallel} = 1).} \\ \end{matrix}

Alors la fonction exponentielle est définie comme suit

La fonction exponentielle d’un quaternion

exp𝐩=exp([0α𝐧̂])[cosα𝐧̂sinα].\begin{matrix} {\exp\mathbf{p}} & {= \exp\left( \begin{bmatrix} 0 & {\alpha\hat{\mathbf{n}}} \\ \end{bmatrix} \right) \equiv \begin{bmatrix} {\cos\alpha} & {\hat{\mathbf{n}}\sin\alpha} \\ \end{bmatrix}.} \\ \end{matrix}

Notez que, par définition, exp𝐩\exp\mathbf{p} retourne toujours un quaternion unitaire.

Le logarithme et l’exponentielle de quaternions sont liés à leurs analogues scalaires. Pour tout scalaire aa ,

elna=a.e^{\ln a} = a.

De même, la fonction exp de quaternion est définie comme étant l’inverse de la fonction log de quaternion :

exp(log𝐪)=𝐪.\exp(\,\log\mathbf{q}\,) = \mathbf{q}.

Enfin, les quaternions peuvent être multipliés par un scalaire, le résultat étant calculé de manière évidente en multipliant chaque composante par le scalaire. Pour un scalaire kk et un quaternion 𝐪\mathbf{q} ,

Multiplication d’un quaternion par un scalaire

k𝐪=k[w𝐯]=[kwk𝐯].\begin{matrix} {k\mathbf{q}} & {= k\begin{bmatrix} w & \mathbf{v} \\ \end{bmatrix} = \begin{bmatrix} {kw} & {k\mathbf{v}} \\ \end{bmatrix}.} \\ \end{matrix}

Cela ne résultera généralement pas en un quaternion unitaire, c’est pourquoi la multiplication par un scalaire n’est pas une opération très utile dans le contexte de la représentation d’un déplacement angulaire. (Mais nous en trouverons une utilité à la Section 8.5.11.)

8.5.11Exponentiation de quaternions

Les quaternions peuvent être exponentiés, ce qui signifie que l’on peut élever un quaternion à une puissance scalaire. L’exponentiation de quaternions, notée 𝐪t\mathbf{q}^{t} , ne doit pas être confondue avec la fonction exponentielle exp𝐪\exp\mathbf{q} . La fonction exponentielle n’accepte qu’un seul argument : un quaternion. L’exponentiation de quaternions a deux arguments : le quaternion 𝐪\mathbf{q} et l’exposant scalaire tt .

La signification de l’exponentiation de quaternions est similaire à celle des nombres réels. Rappelons que pour tout scalaire aa , différent de zéro, a0=1a^{0} = 1 et a1=aa^{1} = a . Lorsque l’exposant tt varie de 00 à 11, la valeur de ata^{t} varie de 11 à aa . Une affirmation similaire vaut pour l’exponentiation de quaternions : lorsque tt varie de 00 à 11, l’exponentiation de quaternions 𝐪t\mathbf{q}^{t} varie de [1,0]\lbrack 1,0\rbrack à 𝐪\mathbf{q} .

L’exponentiation de quaternions est utile car elle nous permet d’extraire une « fraction » d’un déplacement angulaire. Par exemple, pour calculer un quaternion représentant un tiers du déplacement angulaire représenté par le quaternion 𝐪\mathbf{q} , nous calculerions 𝐪1/3\mathbf{q}^{1/3} .

Les exposants hors de la plage [0,1]\lbrack 0,1\rbrack se comportent généralement comme prévu — avec un bémol majeur. Par exemple, 𝐪2\mathbf{q}^{2} représente deux fois le déplacement angulaire de 𝐪\mathbf{q} . Si 𝐪\mathbf{q} représente une rotation de 30° dans le sens des aiguilles d’une montre autour de l’axe xx , alors 𝐪2\mathbf{q}^{2} représente une rotation de 60° dans le sens des aiguilles d’une montre autour de l’axe xx , et 𝐪1/3\mathbf{q}^{- 1/3} représente une rotation de 10° dans le sens contraire des aiguilles d’une montre autour de l’axe xx . Notons en particulier que la notation d’inverse 𝐪1\mathbf{q}^{- 1} peut également être interprétée dans ce contexte et le résultat est le même : le quaternion qui effectue la rotation opposée.

Le bémol que nous avons mentionné est le suivant : un quaternion représente les déplacements angulaires en utilisant l’arc le plus court. Les rotations multiples ne peuvent pas être représentées. Pour continuer notre exemple ci-dessus, 𝐪8\mathbf{q}^{8} n’est pas une rotation de 240° dans le sens des aiguilles d’une montre autour de l’axe xx comme prévu ; c’est une rotation de 120°\ dans le sens contraire des aiguilles d’une montre. Bien sûr, tourner de 240° dans un sens produit le même résultat final que tourner de 120° dans le sens opposé, et c’est là le point : les quaternions ne capturent vraiment que le résultat final. En général, beaucoup des identités algébriques concernant l’exponentiation de scalaires, telles que (as)t=ast(a^{s})^{t} = a^{st} , ne s’appliquent pas aux quaternions.

Dans certaines situations, nous nous soucions effectivement de la quantité totale de rotation, pas seulement du résultat final. (L’exemple le plus important est celui de la vitesse angulaire.) Dans ces situations, les quaternions ne sont pas le bon outil ; utilisez plutôt la carte exponentielle (ou sa variante, le format axe-angle).

Maintenant que nous comprenons l’utilité de l’exponentiation de quaternions, voyons comment elle est définie mathématiquement. L’exponentiation de quaternions est définie en termes des opérations « utilitaires » que nous avons apprises à la section précédente. La définition est donnée par

Élever un quaternion à une puissance

𝐪t=exp(tlog𝐪).\begin{matrix} {\mathbf{q}^{t} = \exp\left( t\log\mathbf{q} \right).} \\ \end{matrix}

Notez qu’une affirmation similaire est vraie concernant l’exponentiation d’un scalaire :

at=e(tlna).a^{t} = e^{(t\ln a)}.

Il n’est pas trop difficile de comprendre pourquoi 𝐪t\mathbf{q}^{t} interpole de l’identité à 𝐪\mathbf{q} lorsque tt varie de 00 à 11 . Notons que l’opération log\log convertit essentiellement le quaternion en format carte exponentielle (à un facteur 2 près). Ensuite, lorsque nous effectuons la multiplication scalaire par l’exposant tt , l’effet est de multiplier l’angle par tt . Enfin, l’opération exp\exp « défait » ce que l’opération log\log a fait, en recalculant les nouveaux ww et 𝐯\mathbf{v} à partir du vecteur exponentiel. C’est du moins ainsi que cela fonctionne académiquement dans une équation. Bien que l’Équation (8.8) soit la définition mathématique officielle et fonctionne élégamment en théorie, la traduction directe en code est plus compliquée que nécessaire. Le listing 8.2 montre comment nous pourrions calculer la valeur de 𝐪t\mathbf{q}^{t} en C. Essentiellement, au lieu de travailler avec une seule quantité de type carte exponentielle comme la formule nous le dit, nous extrayons l’axe et le demi-angle séparément.

// Quaternion (entrée et sortie)
float w,x,y,z;

// Exposant d'entrée
float exponent;

// Vérifier le cas d'un quaternion identité.
// Cela protège contre la division par zéro
if (fabs(w) < .9999f) {

    // Extraire le demi-angle alpha (alpha = theta/2)
    float alpha = acos(w);

    // Calculer la nouvelle valeur d'alpha
    float newAlpha = alpha * exponent;

    // Calculer la nouvelle valeur de w
    w = cos(newAlpha);

    // Calculer les nouvelles valeurs xyz
    float mult = sin(newAlpha) / sin(alpha);
    x *= mult;
    y *= mult;
    z *= mult;
}

Il y a quelques points à noter concernant ce code. Premièrement, la vérification du quaternion identité est nécessaire car une valeur de w=±1w = \pm 1 entraînerait une division par zéro dans le calcul de mult. Élever un quaternion identité à n’importe quelle puissance résulte en le quaternion identité, donc si nous détectons un quaternion identité en entrée, nous ignorons simplement l’exposant et retournons le quaternion original.

Deuxièmement, lorsque nous calculons alpha, nous utilisons la fonction arccos\arccos , qui retourne toujours un angle positif. Cela ne crée pas de perte de généralité. Tout quaternion peut être interprété comme ayant un angle de rotation positif, puisqu’une rotation négative autour d’un axe est identique à une rotation positive autour de l’axe pointant dans la direction opposée.

8.5.12Interpolation de quaternions, a.k.a. Slerp

La raison d’être des quaternions dans les jeux et le graphisme aujourd’hui est une opération connue sous le nom de slerp, qui signifie interpolation Sphérique Linéaire (Spherical Linear interpolation). L’opération slerp est utile car elle nous permet d’interpoler en douceur entre deux orientations. Le slerp évite tous les problèmes qui affectaient l’interpolation des angles d’Euler (voir Section 8.3.4).

Le slerp est un opérateur ternaire, ce qui signifie qu’il accepte trois opérandes. Les deux premiers opérandes du slerp sont les deux quaternions entre lesquels nous souhaitons interpoler. Nous attribuerons ces orientations de départ et d’arrivée aux variables 𝐪0\mathbf{q}_{0} et 𝐪1\mathbf{q}_{1} , respectivement. Le paramètre d’interpolation sera attribué à la variable tt , et lorsque tt varie de 00 à 11 , la fonction slerp slerp(𝐪0,𝐪1,t){slerp}(\mathbf{q}_{0},\mathbf{q}_{1},t) retourne une orientation qui interpole de 𝐪0\mathbf{q}_{0} à 𝐪1\mathbf{q}_{1} .

Voyons si nous pouvons dériver la formule slerp en utilisant les outils que nous avons jusqu’à présent. Si nous interpolions entre deux valeurs scalaires a0a_{0} et a1a_{1} , nous pourrions utiliser la formule standard d’interpolation linéaire (lerp) :

Interpolation linéaire simple

Δa=a1a0,lerp(a0,a1,t)=a0+tΔa.\begin{matrix} {\Delta a} & {= a_{1} - a_{0},} \\ {{lerp}(a_{0},a_{1},t)} & {= a_{0} + t\,\Delta a.} \\ \end{matrix}

La formule standard d’interpolation linéaire fonctionne en partant de a0a_{0} et en ajoutant la fraction tt de la différence entre a1a_{1} et a0a_{0} . Cela nécessite trois étapes de base :

  1. Calculer la différence entre les deux valeurs.

  2. Prendre une fraction de cette différence.

  3. Prendre la valeur originale et l’ajuster de cette fraction de la différence.

Nous pouvons utiliser la même idée de base pour interpoler entre des orientations. (Rappelons encore que la multiplication de quaternions se lit de droite à gauche.)

  1. Calculer la différence entre les deux valeurs. Nous avons montré comment faire cela à la Section 8.5.8. Le déplacement angulaire de 𝐪0\mathbf{q}_{0} à 𝐪1\mathbf{q}_{1} est donné par

    Δ𝐪=𝐪1𝐪01.\Delta\mathbf{q} = \mathbf{q}_{1}{\mathbf{q}_{0}}^{- 1}.

  2. Prendre une fraction de cette différence. Pour cela, nous utilisons l’exponentiation de quaternions, dont nous avons parlé à la Section 8.5.11. La fraction de la différence est donnée par

    (Δ𝐪)t.(\Delta\mathbf{q})^{t}.

  3. Prendre la valeur originale et l’ajuster de cette fraction de la différence. Nous « ajustons » la valeur initiale en composant les déplacements angulaires via la multiplication de quaternions :

    (Δ𝐪)t𝐪0.(\Delta\mathbf{q})^{t}\mathbf{q}_{0}.

Ainsi, l’équation du slerp est donnée par

Slerp de quaternions en théorie

slerp(𝐪0,𝐪1,t)=(𝐪1𝐪01)t𝐪0.{slerp}(\mathbf{q}_{0},\mathbf{q}_{1},t) = (\mathbf{q}_{1}{\mathbf{q}_{0}}^{- 1})^{t}\mathbf{q}_{0}.

Cette forme algébrique est la façon dont le slerp est calculé en théorie. En pratique, nous utilisons une formulation qui est mathématiquement équivalente, mais plus efficace sur le plan computationnel. Pour dériver cette formule alternative, nous commençons par interpréter les quaternions comme existant dans un espace euclidien 4D. Puisque tous les quaternions qui nous intéressent sont des quaternions unitaires, ils « vivent » sur la surface d’une hypersphère 4D. L’idée de base est d’interpoler autour de l’arc qui relie les deux quaternions, le long de la surface de l’hypersphère 4D. (D’où le nom d’interpolation sphérique linéaire.)

Nous pouvons visualiser cela dans le plan (voir Figure 8.11). Imaginons deux vecteurs 2D 𝐯0\mathbf{v}_{0} et 𝐯1\mathbf{v}_{1} , tous deux de longueur unitaire. Nous souhaitons calculer la valeur de 𝐯t\mathbf{v}_{t} , qui est le résultat de l’interpolation en douceur autour de l’arc d’une fraction tt de la distance de 𝐯0\mathbf{v}_{0} à 𝐯1\mathbf{v}_{1} . Si nous laissons ω\omega 13 être l’angle sous-tendu par l’arc de 𝐯0\mathbf{v}_{0} à 𝐯1\mathbf{v}_{1} , alors 𝐯t\mathbf{v}_{t} est le résultat de la rotation de 𝐯0\mathbf{v}_{0} autour de cet arc d’un angle de tωt\omega .

image

Figure 8.11Interpolation d’une rotation

Nous pouvons exprimer 𝐯t\mathbf{v}_{t} comme une combinaison linéaire de 𝐯0\mathbf{v}_{0} et 𝐯1\mathbf{v}_{1} . En d’autres termes, il existe des constantes non négatives k0k_{0} et k1k_{1} telles que 𝐯t=k0𝐯0+k1𝐯1\mathbf{v}_{t} = k_{0}\mathbf{v}_{0} + k_{1}\mathbf{v}_{1} . Nous pouvons utiliser la géométrie élémentaire pour déterminer les valeurs de k0k_{0} et k1k_{1} . La Figure 8.12 montre comment cela peut être fait.

image

Figure 8.12Interpolation d’un vecteur le long d’un arc

En appliquant un peu de trigonométrie au triangle rectangle avec k1𝐯1k_{1}\mathbf{v}_{1} comme hypoténuse (et en rappelant que 𝐯1\mathbf{v}_{1} est un vecteur unitaire), nous voyons que

sinω=sintωk1,k1=sintωsinω.\begin{matrix} {\sin\omega} & {= \frac{\sin t\omega}{k_{1}},} \\ k_{1} & {= \frac{\sin t\omega}{\sin\omega}.} \\ \end{matrix}

Une technique similaire pour résoudre k0k_{0} donne le résultat suivant :

k0=sin(1t)ωsinω.k_{0} = \frac{\sin(1 - t)\omega}{\sin\omega}.

Ainsi, 𝐯t\mathbf{v}_{t} peut s’exprimer comme

𝐯t=k0𝐯0+k1𝐯1=sin(1t)ωsinω𝐯0+sintωsinω𝐯1.\mathbf{v}_{t} = k_{0}\mathbf{v}_{0} + k_{1}\mathbf{v}_{1} = \frac{\sin(1 - t)\omega}{\sin\omega}\mathbf{v}_{0} + \frac{\sin t\omega}{\sin\omega}\mathbf{v}_{1}.

La même idée de base peut être étendue à l’espace des quaternions, et nous pouvons reformuler le slerp comme

Slerp de quaternions en pratique

slerp(𝐪0,𝐪1,t)=sin(1t)ωsinω𝐪0+sintωsinω𝐪1.{slerp}(\mathbf{q}_{0},\mathbf{q}_{1},t) = \frac{\sin(1 - t)\omega}{\sin\omega}\mathbf{q}_{0} + \frac{\sin t\omega}{\sin\omega}\mathbf{q}_{1}.

Nous avons juste besoin d’un moyen de calculer ω\omega , l’« angle » entre les deux quaternions. Il se trouve qu’une analogie issue des mathématiques vectorielles 2D peut être portée dans l’espace des quaternions ; nous pouvons penser au produit scalaire de quaternions comme retournant cosω\cos\omega .

Il y a deux légères complications. Premièrement, les deux quaternions 𝐪\mathbf{q} et 𝐪- \mathbf{q} représentent la même orientation, mais peuvent produire des résultats différents lorsqu’ils sont utilisés comme arguments de slerp. Ce problème ne survient pas en 2D ou 3D, mais la surface d’une hypersphère 4D a une topologie différente de l’espace euclidien. La solution consiste à choisir les signes de 𝐪0\mathbf{q}_{0} et 𝐪1\mathbf{q}_{1} de sorte que le produit scalaire 𝐪0𝐪1\mathbf{q}_{0} \cdot \mathbf{q}_{1} soit non négatif. Cela a pour effet de toujours sélectionner l’arc rotationnel le plus court de 𝐪0\mathbf{q}_{0} à 𝐪1\mathbf{q}_{1} . La seconde complication est que si 𝐪0\mathbf{q}_{0} et 𝐪1\mathbf{q}_{1} sont très proches, alors ω\omega est très petit, et donc sinω\sin\omega est également très petit, ce qui posera des problèmes lors de la division. Pour éviter cela, si sinω\sin\omega est très petit, nous utiliserons une simple interpolation linéaire. L’extrait de code au Listing 8.3 applique tous ces conseils pour calculer le slerp de quaternions.

// Les deux quaternions d'entrée
float w0,x0,y0,z0;
float w1,x1,y1,z1;

// Le paramètre d'interpolation
float t;

// Le quaternion de sortie sera calculé ici
float w,x,y,z;

// Calculer le « cosinus de l'angle » entre les
// quaternions, en utilisant le produit scalaire
float cosOmega = w0*w1 + x0*x1 + y0*y1 + z0*z1;
// Si le produit scalaire est négatif, nier l'un des quaternions
// d'entrée, pour prendre le plus court « arc » en 4D
if (cosOmega < 0.0f) {
    w1 = -w1;
    x1 = -x1;
    y1 = -y1;
    z1 = -z1;
    cosOmega = -cosOmega;
}

// Vérifier s'ils sont très proches, pour se protéger
// contre la division par zéro
float k0, k1;
if (cosOmega > 0.9999f) {

    // Très proches - utiliser simplement l'interpolation linéaire
    k0 = 1.0f-t;
    k1 = t;

} else {

    // Calculer le sinus de l'angle en utilisant l'identité
    // trigonométrique sin^2(omega) + cos^2(omega) = 1
    float sinOmega = sqrt(1.0f - cosOmega*cosOmega);

    // Calculer l'angle à partir de son sinus et cosinus
    float omega = atan2(sinOmega, cosOmega);

    // Calculer l'inverse du dénominateur, pour ne diviser
    // qu'une seule fois
    float oneOverSinOmega = 1.0f / sinOmega;

    // Calculer les paramètres d'interpolation
    k0 = sin((1.0f - t) * omega) * oneOverSinOmega;
    k1 = sin(t * omega) * oneOverSinOmega;
}

// Interpoler
w = w0*k0 + w1*k1;
x = x0*k0 + x1*k1;
y = y0*k0 + y1*k1;
z = z0*k0 + z1*k1;

8.5.13Avantages et inconvénients des quaternions

Les quaternions offrent un certain nombre d’avantages par rapport aux autres méthodes de représentation des déplacements angulaires :

Ces avantages ont cependant un coût. Les quaternions souffrent de quelques-uns des problèmes qui affectent les matrices, mais dans une moindre mesure :

8.5.14Les quaternions en tant que nombres complexes

Nous terminons notre discussion sur les quaternions là où la plupart des ouvrages commencent : une discussion de leur interprétation en tant que nombres complexes. Si vous vous intéressez aux quaternions uniquement pour les rotations, vous pouvez ignorer cette section en toute sécurité. Si vous voulez une compréhension plus approfondie ou si vous êtes intéressé par l’héritage mathématique des quaternions et les circonstances qui ont entouré leur invention, cette section sera intéressante. Nous suivrons une approche due à John McDonald de l’Université DePaul [9]. Entre autres, cette méthode est capable d’expliquer deux particularités des quaternions : l’apparition de θ/2\theta/2 plutôt que θ\theta et la forme mathématique inhabituelle 𝐪𝐯𝐪1\mathbf{q}\mathbf{v}\mathbf{q}^{- 1} :

Nous commençons par examiner comment nous pouvons intégrer l’ensemble des nombres réels dans l’ensemble des matrices 2×22 \times 2 . Pour tout scalaire donné aa , nous l’associons à exactement une matrice 2×22 \times 2 , à savoir la matrice qui a aa sur les deux éléments diagonaux :

Chaque scalaire réel est associé à une matrice 2×22 \times 2

a[a00a].a \equiv \begin{bmatrix} a & 0 \\ 0 & a \\ \end{bmatrix}.

Nous avons choisi un sous-ensemble des matrices 2×22 \times 2 et établi une correspondance bijective entre ce plus petit ensemble de matrices et l’ensemble de tous les nombres réels. Nous aurions pu établir cette relation bijective d’autres façons, mais cette façon particulière est importante car elle préserve toutes les lois algébriques ordinaires de l’addition, la soustraction et la multiplication : la propriété associative, la propriété distributive, la non-factorisabilité du zéro, etc. (Nous pouvons même inclure la division si nous la traitons comme une multiplication par l’inverse.) Par exemple,

Addition, soustraction et multiplication fonctionnent de la même manière

[a00a]+[b00b]=[a+b00a+b],[a00a][b00b]=[ab00ab],[a00a][b00b]=[ab00ab].\begin{matrix} {\begin{bmatrix} a & 0 \\ 0 & a \\ \end{bmatrix} + \begin{bmatrix} b & 0 \\ 0 & b \\ \end{bmatrix}} & {= \begin{bmatrix} {a + b} & 0 \\ 0 & {a + b} \\ \end{bmatrix},} \\ {\begin{bmatrix} a & 0 \\ 0 & a \\ \end{bmatrix} - \begin{bmatrix} b & 0 \\ 0 & b \\ \end{bmatrix}} & {= \begin{bmatrix} {a - b} & 0 \\ 0 & {a - b} \\ \end{bmatrix},} \\ {\begin{bmatrix} a & 0 \\ 0 & a \\ \end{bmatrix}\begin{bmatrix} b & 0 \\ 0 & b \\ \end{bmatrix}} & {= \begin{bmatrix} {ab} & 0 \\ 0 & {ab} \\ \end{bmatrix}.} \\ \end{matrix}

Voyons maintenant si nous pouvons créer une correspondance similaire pour l’ensemble des nombres complexes. Vous avez probablement déjà été initié aux nombres complexes ; si c’est le cas, vous devriez vous rappeler que la paire complexe (a,b)(a,b) définit le nombre a+bia + bi . Le nombre ii est un nombre spécial tel que i2=1i^{2} = - 1 . On l’appelle souvent le nombre imaginaire car aucun scalaire ordinaire (un nombre « réel ») ne peut avoir cette propriété. Le mot « imaginaire » donne l’impression que le nombre n’existe pas vraiment ; nous allons éviter ce terme et nous en tenir à un plus descriptif : « complexe ».

Les nombres complexes peuvent être additionnés, soustraits et multipliés. Il suffit de suivre les règles ordinaires de l’arithmétique, et de remplacer i2i^{2} par 1- 1 chaque fois qu’il apparaît. Cela donne les identités suivantes :

Addition, soustraction et multiplication de nombres complexes

(a+bi)+(c+di)=(a+c)+(b+d)i,(a+bi)(c+di)=(ac)+(bd)i,(a+bi)(c+di)=ac+adi+bci+bdi2=ac+(ad+bc)i+bd(1)=(acbd)+(ad+bc)i.\begin{matrix} {(a + bi) + (c + di)} & {= (a + c) + (b + d)i,} \\ {(a + bi) - (c + di)} & {= (a - c) + (b - d)i,} \\ {(a + bi)(c + di)} & {= ac + adi + bci + bdi^{2}} \\ & {= ac + (ad + bc)i + bd( - 1)} \\ & {= (ac - bd) + (ad + bc)i.} \\ \end{matrix}

Maintenant, comment pouvons-nous étendre notre système d’intégration des nombres dans l’espace des matrices 2×22 \times 2 pour inclure les nombres complexes ? Auparavant, nous n’avions qu’un seul degré de liberté, aa , et maintenant nous en avons deux, aa et bb . La correspondance que nous utilisons est

Association de chaque nombre complexe à une matrice 2×22 \times 2

a+bi[abba].\begin{matrix} {a + bi \equiv \begin{bmatrix} a & {- b} \\ b & a \\ \end{bmatrix}.} \\ \end{matrix}

Nous pouvons facilement vérifier que le nombre complexe à gauche se comporte exactement de la même manière que la matrice à droite. En un certain sens, ce ne sont que deux notations pour écrire la même quantité :

Addition, soustraction et multiplication en notation standard et sous notre forme 2×22 \times 2

(a+bi)+(c+di)[abba]+[cddc]=[a+c(b+d)b+da+c](a+c)+(b+d)i,(a+bi)(c+di)[abba][cddc]=[ac(bd)bdac](ac)+(bd)i,(a+bi)(c+di)[abba][cddc]=[acbd(ad+bc)ad+bcacbd](acbd)+(ad+bc)i.\begin{matrix} {(a + bi) + (c + di)} & {\equiv \begin{bmatrix} a & {- b} \\ b & a \\ \end{bmatrix} + \begin{bmatrix} c & {- d} \\ d & c \\ \end{bmatrix} = \begin{bmatrix} {a + c} & {- (b + d)} \\ {b + d} & {a + c} \\ \end{bmatrix}} \\ & {\equiv (a + c) + (b + d)i,} \\ {(a + bi) - (c + di)} & {\equiv \begin{bmatrix} a & {- b} \\ b & a \\ \end{bmatrix} - \begin{bmatrix} c & {- d} \\ d & c \\ \end{bmatrix} = \begin{bmatrix} {a - c} & {- (b - d)} \\ {b - d} & {a - c} \\ \end{bmatrix}} \\ & {\equiv (a - c) + (b - d)i,} \\ {(a + bi)(c + di)} & {\equiv \begin{bmatrix} a & {- b} \\ b & a \\ \end{bmatrix}\begin{bmatrix} c & {- d} \\ d & c \\ \end{bmatrix} = \begin{bmatrix} {ac - bd} & {- (ad + bc)} \\ {ad + bc} & {ac - bd} \\ \end{bmatrix}} \\ & {\equiv (ac - bd) + (ad + bc)i.} \\ \end{matrix}

Nous vérifions également que l’équation i2=1i^{2} = - 1 est toujours valide :

𝐢\mathbf{i} ne semble pas si « imaginaire » sous forme 2×22 \times 2

i2[0110]2=[0110][0110]=[1001]1.i^{2} \equiv \begin{bmatrix} 0 & {- 1} \\ 1 & 0 \\ \end{bmatrix}^{2} = \begin{bmatrix} 0 & {- 1} \\ 1 & 0 \\ \end{bmatrix}\begin{bmatrix} 0 & {- 1} \\ 1 & 0 \\ \end{bmatrix} = \begin{bmatrix} {- 1} & 0 \\ 0 & {- 1} \\ \end{bmatrix} \equiv - 1.

Appliquons la perspective géométrique du Chapitre 5. En interprétant les colonnes14 [0,1]\lbrack 0,1\rbrack et [1,0]\lbrack - 1,0\rbrack comme les vecteurs de base d’un espace de coordonnées, nous voyons que cette matrice effectue une rotation de 90o90^{o} .

Nous pouvons interpréter la multiplication par ii comme une rotation de 90o90^{o} .14

Il n’y a rien d’« imaginaire » là-dedans. Au lieu de penser à ii comme à la racine carrée de 1- 1 , pensez plutôt au nombre complexe a+bia + bi comme à une entité mathématique avec deux degrés de liberté qui se comporte de manière particulière lorsqu’elle est multipliée. La partie que nous appelons habituellement la partie « réelle », aa , est le degré de liberté principal, et bb mesure un degré de liberté secondaire. Les deux degrés de liberté sont en un certain sens « orthogonaux » l’un à l’autre.

En poursuivant plus loin, nous voyons que nous pouvons représenter des rotations par n’importe quel angle arbitraire θ\theta en utilisant ce schéma. La matrice de rotation 2×22 \times 2 de base dérivée à la Section 5.1.1 se trouve être dans cet ensemble spécial de matrices que nous associons aux nombres complexes. Elle est associée au nombre complexe cosθ+isinθ\cos\theta + i\sin\theta :

Nombres complexes unitaires en tant que rotations

cosθ+isinθ[cosθsinθsinθcosθ].\cos\theta + i\sin\theta \equiv \begin{bmatrix} {\cos\theta} & {- \sin\theta} \\ {\sin\theta} & {\cos\theta} \\ \end{bmatrix}.

Remarquez comment la conjugaison complexe (négation de la partie complexe) correspond à la transposition matricielle. C’est particulièrement élégant. Rappelons que le conjugué d’un quaternion exprime le déplacement angulaire inverse. Un fait correspondant est vrai pour la transposition des matrices de rotation : comme elles sont orthogonales, leur transposée est égale à leur inverse.

Comment les vecteurs 2D ordinaires s’intègrent-ils dans ce schéma ? Nous interprétons le vecteur [x,y]\lbrack x,y\rbrack comme le nombre complexe x+iyx + iy , et nous pouvons alors interpréter la multiplication de deux nombres complexes

(cosθ+isinθ)(x+iy)=xcosθ+iycosθ+ixsinθ+i2ysinθ=(xcosθysinθ)+i(xsinθ+ycosθ)\begin{matrix} {(\cos\theta + i\sin\theta)(x + iy)} & {= x\cos\theta + iy\cos\theta + ix\sin\theta + i^{2}y\sin\theta} \\ & {= (x\cos\theta - y\sin\theta) + i(x\sin\theta + y\cos\theta)} \\ \end{matrix}

comme effectuant une rotation. Cela est équivalent à la multiplication matricielle

[cosθsinθsinθcosθ][xy]=[xcosθysinθxsinθ+ycosθ].\begin{bmatrix} {\cos\theta} & {- \sin\theta} \\ {\sin\theta} & {\cos\theta} \\ \end{bmatrix}\begin{bmatrix} x \\ y \\ \end{bmatrix} = \begin{bmatrix} {x\cos\theta - y\sin\theta} \\ {x\sin\theta + y\cos\theta} \\ \end{bmatrix}.

Bien que ce ne soit pas beaucoup plus que des anecdotes mathématiques pour l’instant, notre objectif est d’établir des parallèles que nous pourrons ensuite transposer aux quaternions, alors répétons le résultat clé.

En 2D, nous pouvons interpréter le vecteur [x,y]\lbrack x,y\rbrack comme un nombre complexe x+yix + yi et le faire tourner en utilisant la multiplication complexe (cosθ+isinθ)(x+iy)(\cos\theta + i\sin\theta)(x + iy) .

Une conversion similaire des vecteurs ordinaires vers les nombres complexes est nécessaire pour multiplier les quaternions et les vecteurs 3D.

Avant de quitter la 2D, résumons ce que nous avons appris jusqu’à présent. Les nombres complexes sont des objets mathématiques avec deux degrés de liberté qui obéissent à certaines règles lorsque nous les multiplions. Ces objets sont généralement écrits sous la forme a+bia + bi , mais peuvent être écrits de manière équivalente sous la forme d’une matrice 2×22 \times 2 . Lorsque nous écrivons les nombres complexes sous forme de matrices, cela appelle l’interprétation géométrique de la multiplication par ii comme une rotation de 90o90^{o} . La règle i2=1i^{2} = - 1 a l’interprétation que combiner deux rotations de 90o90^{o} donne une rotation de 180o180^{o} , ce qui nous réconforte. Plus généralement, tout nombre complexe de longueur unitaire peut s’écrire cosθ+isinθ\cos\theta + i\sin\theta et être interprété comme une rotation par l’angle θ\theta . Si nous convertissons un vecteur 2D en forme complexe et le multiplions par cosθ+isinθ\cos\theta + i\sin\theta , cela a pour effet d’effectuer la rotation.

Il est très tentant d’étendre cette technique de la 2D à la 3D. Tentant, mais hélas impossible de manière directe. Le mathématicien irlandais William Hamilton (1805–1865) a apparemment succombé à cette même tentation, et avait cherché pendant des années un moyen d’étendre les nombres complexes de la 2D à la 3D. Ce nouveau type de nombre complexe, pensait-il, aurait une partie réelle et deux parties imaginaires. Cependant, Hamilton ne put créer un type utile de nombre complexe avec deux parties imaginaires. Puis, selon la légende, en 1843, sur le chemin d’un discours à la Royal Irish Academy, il réalisa soudainement que trois parties imaginaires étaient nécessaires plutôt que deux. Il grava les équations définissant les propriétés de ce nouveau type de nombre complexe sur le Pont de Broom. Ses marques originales ont disparu dans la légende, mais une plaque commémorative les perpétue. C’est ainsi que les quaternions furent inventés.

Puisque nous n’étions pas sur le Pont de Broom en 1843, nous ne pouvons pas dire avec certitude ce qui a fait réaliser à Hamilton qu’un système 3D de nombres complexes ne fonctionnait pas, mais nous pouvons montrer pourquoi un tel ensemble ne pourrait pas être facilement associé aux matrices 3×33 \times 3 et aux rotations. Un nombre complexe 3D aurait deux parties complexes, ii et jj , avec les propriétés i2=j2=1i^{2} = j^{2} = - 1 . (Nous aurions également besoin de définir les valeurs des produits ijij et jiji . Ce que ces règles devraient être, nous n’en sommes pas sûrs ; peut-être Hamilton a-t-il réalisé que c’était une impasse. De toute façon, cela n’a pas d’importance pour la présente discussion.) Or, une extension directe des idées de la 2D signifierait que nous pourrions d’une manière ou d’une autre associer les nombres 1, ii et jj à l’ensemble des matrices 3×33 \times 3 , de sorte que toutes les lois algébriques habituelles soient respectées. Le nombre 1 doit évidemment être associé à la matrice identité 3D 𝐈3\mathbf{I}_{3} . Le nombre 1- 1 devrait être associé à son opposé, 𝐈3- \mathbf{I}_{3} , qui a des 1- 1 sur la diagonale. Mais nous rencontrons maintenant un problème pour trouver des matrices pour ii et jj dont le carré est 𝐈3- \mathbf{I}_{3} . Nous pouvons rapidement voir que cela n’est pas possible car le déterminant de 𝐈3- \mathbf{I}_{3} est 1- 1 . Pour être une racine de cette matrice, ii ou jj doit avoir un déterminant qui est la racine carrée de 1- 1 , car le déterminant d’un produit matriciel est le produit des déterminants. La seule façon que cela fonctionne est que ii et jj contiennent des entrées complexes. En bref, il ne semble pas exister de système cohérent de nombres complexes 3D ; il n’en existe certainement pas un qui s’associe élégamment aux rotations analogiquement aux nombres complexes standard et aux rotations 2D. Pour cela, nous avons besoin des quaternions.

Les quaternions étendent le système des nombres complexes en ayant trois nombres imaginaires, ii , jj et kk , qui sont liés par les fameuses équations de Hamilton :

Les règles pour les nombres complexes 4D que Hamilton a gravées sur le Pont de Broom

i2=j2=k2=1ij=k,ji=k,jk=i,kj=i,ki=j,ik=j.\begin{matrix} \begin{matrix} & {i^{2} = j^{2} = k^{2} = - 1} \\ & {ij = k,\quad ji = - k,} \\ & {jk = i,\quad kj = - i,} \\ & {ki = j,\quad ik = - j.} \\ \end{matrix} \\ \end{matrix}

Le quaternion que nous avons noté [w,(x,y,z)]\lbrack w,(x,y,z)\rbrack correspond au nombre complexe w+xi+yj+zkw + xi + yj + zk . La définition du produit de quaternions donnée à la Section 8.5.7 découle de ces règles. (Voir aussi Exercice 6.) Le produit scalaire, cependant, ignore fondamentalement tout ce côté complexe i,j,ki,j,k et traite les opérandes comme de simples vecteurs 4D.

Revenons maintenant aux matrices. Pouvons-nous intégrer l’ensemble des quaternions dans l’ensemble des matrices de sorte que les règles de Hamilton de l’Équation (8.10) soient toujours respectées ? Oui, nous le pouvons, bien que, comme vous pouvez vous y attendre, nous les associions aux matrices 4×44 \times 4 . Les nombres réels sont associés à une matrice avec le nombre sur chaque entrée de la diagonale comme auparavant,

a[a0000a0000a0000a],a \equiv \begin{bmatrix} a & 0 & 0 & 0 \\ 0 & a & 0 & 0 \\ 0 & 0 & a & 0 \\ 0 & 0 & 0 & a \\ \end{bmatrix},

et les quantités complexes sont associées aux matrices

Association des trois quantités complexes à des matrices 4×44 \times 4

i[0001001001001000],j[0010000110000100],k[0100100000010010].\begin{matrix} i & {\equiv \begin{bmatrix} 0 & 0 & 0 & 1 \\ 0 & 0 & {- 1} & 0 \\ 0 & 1 & 0 & 0 \\ {- 1} & 0 & 0 & 0 \\ \end{bmatrix},} & j & {\equiv \begin{bmatrix} 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \\ {- 1} & 0 & 0 & 0 \\ 0 & {- 1} & 0 & 0 \\ \end{bmatrix},} & k & {\equiv \begin{bmatrix} 0 & {- 1} & 0 & 0 \\ 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 0 & {- 1} & 0 \\ \end{bmatrix}.} \\ \end{matrix}

Nous vous encourageons à vérifier que ces associations préservent bien toutes les règles de Hamilton avant de continuer.

En combinant les associations ci-dessus, nous pouvons associer un quaternion arbitraire à une matrice 4×44 \times 4 comme suit

Encodage des quaternions sous forme de matrices 4×44 \times 4

w+xi+yj+zk[wzyxzwxyyxwzxyzw].\begin{matrix} {w + xi + yj + zk \equiv \begin{bmatrix} w & {- z} & y & x \\ z & w & {- x} & y \\ {- y} & x & w & z \\ {- x} & {- y} & {- z} & w \\ \end{bmatrix}.} \\ \end{matrix}

Encore une fois, nous remarquons comment la conjugaison complexe (nier xx , yy , et zz ) correspond à la transposition matricielle.

Tout ce que nous avons dit jusqu’à présent s’applique aux quaternions de n’importe quelle longueur. Revenons maintenant aux rotations. Nous pouvons voir que les matrices ii , jj , kk de l’Équation (8.11) permutent et nient des axes, de sorte qu’elles présentent une certaine ressemblance avec les rotations de 90o90^{o} ou les réflexions. Voyons si nous pouvons transposer les idées simples de la 2D avec ces matrices. Notez comment la partie supérieure gauche 2×22 \times 2 de la matrice kk est identique à la toute première matrice 2×22 \times 2 pour ii ; en d’autres termes, une partie de kk est une rotation de 90o90^{o} autour de zz . Par analogie avec le cas 2D, on pourrait raisonnablement s’attendre à ce que le quaternion cosθ+ksinθ\cos\theta + k\sin\theta représente une rotation autour de l’axe zz par un angle arbitraire θ\theta . Multiplions-le par le vecteur [1,0,0]\lbrack 1,0,0\rbrack et voyons ce qui se passe. Comme dans le cas 2D, nous devons « promouvoir » le vecteur dans le domaine complexe ; ce qui est différent ici est que les quaternions ont un nombre supplémentaire. Nous associons [x,y,z]\lbrack x,y,z\rbrack au nombre complexe 0+xi+yj+zk0 + xi + yj + zk , donc le vecteur [1,0,0]\lbrack 1,0,0\rbrack est simplement ii . En développant la multiplication, nous avons

(cosθ+ksinθ)i=icosθ+kisinθ,=icosθ+jsinθ,\begin{matrix} {(\cos\theta + k\sin\theta)i} & {= i\cos\theta + ki\sin\theta,} \\ & {= i\cos\theta + j\sin\theta,} \\ \end{matrix}

ce qui correspond à [cosθ,sinθ,0]\lbrack\cos\theta,\sin\theta,0\rbrack , exactement ce que nous attendrions en faisant tourner l’axe xx autour de l’axe zz . Jusqu’ici, tout va bien. Essayons un vecteur légèrement plus général [1,0,1]\lbrack 1,0,1\rbrack , qui est représenté dans le domaine complexe par i+ki + k :

(cosθ+ksinθ)(i+k)=icosθ+kcosθ+kisinθ+k2sinθ=icosθ+jsinθ+kcosθsinθ.\begin{matrix} {(\cos\theta + k\sin\theta)(i + k)} & {= i\cos\theta + k\cos\theta + ki\sin\theta + k^{2}\sin\theta} \\ & {= i\cos\theta + j\sin\theta + k\cos\theta - \sin\theta.} \\ \end{matrix}

Ce résultat ne correspond pas du tout à un vecteur, puisqu’il a une valeur non nulle pour ww . La rotation dans le plan xyxy a fonctionné comme prévu, mais malheureusement, la composante zz n’est pas sortie correctement. Il y a une rotation indésirable dans l’hyperplan zwzw . Cela est parfaitement clair en regardant comment (cosθ+ksinθ)(\cos\theta + k\sin\theta) est représenté sous forme de matrice 4×44 \times 4 :

cosθ+ksinθ[cosθsinθ00sinθcosθ0000cosθsinθ00sinθcosθ].\begin{matrix} {\cos\theta + k\sin\theta \equiv \begin{bmatrix} {\cos\theta} & {- \sin\theta} & 0 & 0 \\ {\sin\theta} & {\cos\theta} & 0 & 0 \\ 0 & 0 & {\cos\theta} & {\sin\theta} \\ 0 & 0 & {- \sin\theta} & {\cos\theta} \\ \end{bmatrix}.} \\ \end{matrix}

La matrice de rotation 2×22 \times 2 en haut à gauche est celle que nous voulons ; la matrice de rotation 2×22 \times 2 en bas à droite n’est pas souhaitée.

Nous nous demandons maintenant si nous avons peut-être fait quelque chose de mal. Il existe peut-être d’autres racines 4×44 \times 4 de 1- 1 que nous pourrions utiliser pour ii , jj et kk — d’autres façons d’intégrer l’ensemble des quaternions dans l’ensemble des matrices 4×44 \times 4 . Il existe effectivement d’autres alternatives, et c’est un indice que quelque chose est un peu différent du cas 2D. Malheureusement, toutes ces alternatives présentent des variations de ce qui est essentiellement le même comportement que nous observons ici. Peut-être, à la place, notre problème est-il que nous avons effectué la multiplication dans le mauvais ordre. (Après tout, la multiplication de ii , jj et kk n’est pas commutative.) Essayons de placer le vecteur à gauche et le quaternion de rotation à droite :

(i+k)(cosθ+ksinθ)=icosθ+iksinθ+kcosθ+k2sinθ=icosθjsinθ+kcosθsinθ.\begin{matrix} {(i + k)(\cos\theta + k\sin\theta)} & {= i\cos\theta + ik\sin\theta + k\cos\theta + k^{2}\sin\theta} \\ & {= i\cos\theta - j\sin\theta + k\cos\theta - \sin\theta.} \\ \end{matrix}

En comparant cela avec l’Équation (8.13), lorsque les opérandes étaient dans l’ordre inverse, nous voyons que la seule différence est le signe de la coordonnée yy . À première vue, cela semble en fait pire. La rotation dans le plan xzxz que nous voulions a été inversée ; nous avons maintenant une rotation par θ- \theta . Entre-temps, la rotation supplémentaire que nous ne voulions pas est exactement la même qu’auparavant. Mais vous pouvez peut-être déjà voir la solution. Si nous utilisons la rotation opposée, qui correspond à utiliser le conjugué du quaternion, nous résolvons les deux problèmes :

(i+k)(cosθksinθ)=icosθ+jsinθkcosθ+sinθ.(i + k)(\cos\theta - k\sin\theta) = i\cos\theta + j\sin\theta - k\cos\theta + \sin\theta.

Ainsi, la multiplication à gauche par (cosθ+ksinθ)(\cos\theta + k\sin\theta) produisait la rotation que nous voulions, plus une rotation supplémentaire indésirable, et la multiplication à droite par le conjugué a réalisé la même rotation désirée, avec la rotation indésirable opposée. Si nous combinons ces deux étapes, la rotation indésirable s’annule, et il ne reste que la rotation que nous voulons. Enfin, pas tout à fait, il reste deux fois la rotation que nous voulons, mais cela se corrige facilement en utilisant θ/2\theta/2 au lieu de θ\theta . Bien sûr, nous savions que θ/2\theta/2 apparaîtrait quelque part, mais maintenant nous en voyons la raison. Résumons nos découvertes des paragraphes précédents.

Pour étendre les idées sur les nombres complexes et les rotations de la 2D aux quaternions, nous convertissons d’abord le vecteur [x,y,z]\lbrack x,y,z\rbrack en forme quaternionique sous 𝐯=[0,(x,y,z)]\mathbf{v} = \lbrack 0,(x,y,z)\rbrack . Une approche directe pour faire tourner le vecteur d’un angle θ\theta autour de l’axe 𝐧̂\hat{\mathbf{n}} consisterait à créer le quaternion 𝐪=[cosθ,sinθ𝐧̂]\mathbf{q} = \lbrack\cos\theta,\sin\theta\,\hat{\mathbf{n}}\rbrack et à effectuer la multiplication 𝐪𝐯\mathbf{q}\mathbf{v} . Cependant, cela ne fonctionne pas ; bien que le résultat contienne la rotation que nous voulons, il contient également une rotation indésirable vers ww . La multiplication 𝐯𝐪*\mathbf{v}\mathbf{q}^{\ast} produit également la rotation que nous voulons plus une rotation indésirable, mais dans ce cas la rotation indésirable est exactement opposée à celle produite par 𝐪𝐯\mathbf{q}\mathbf{v} . La solution consiste à utiliser le demi-angle et à définir 𝐪=[cos(θ/2),sin(θ/2)𝐧̂]\mathbf{q} = \lbrack\cos(\theta/2),\sin(\theta/2)\,\hat{\mathbf{n}}\rbrack , et la rotation est réalisée en effectuant les deux multiplications : 𝐪𝐯𝐪*\mathbf{q}\mathbf{v}\mathbf{q}^{\ast} . La première rotation fait tourner à mi-chemin vers l’objectif, plus une rotation indésirable impliquant ww . La deuxième rotation complète la rotation désirée tout en annulant la rotation indésirable.

Avant de quitter cette section, revenons sur un dernier point plus subtil. Nous avons mentionné qu’il existe d’autres façons d’intégrer l’ensemble des quaternions dans l’ensemble des matrices 4×44 \times 4 . (Les Équations  (8.11) et (8.12) ne sont pas les seules façons de le faire.) McDonald [9] explore cette idée plus en détail ; ici nous voulons simplement noter que c’est une autre cause sous-jacente du besoin de 𝐪𝐯𝐪1\mathbf{q}\mathbf{v}\mathbf{q}^{- 1} . En utilisant une seule multiplication, les variations dans l’intégration produiraient des variations dans le résultat de la rotation. Lorsque les deux multiplications sont présentes, le changement d’un style à un autre produit un changement à gauche qui est exactement annulé par le changement correspondant à droite.

8.5.15Résumé des quaternions

La Section 8.5 a couvert beaucoup de mathématiques, et la plupart ne sont pas importants à retenir. Les faits qui sont importants à retenir sur les quaternions sont résumés ici.

Beaucoup plus a été écrit sur les quaternions que nous n’avons eu l’espace d’en discuter ici. Le rapport technique de Dam et al. [2] est un bon résumé mathématique. Le livre de Kuiper [8] est écrit depuis une perspective aérospatiale et fait également un bon travail de connexion entre les quaternions et les angles d’Euler. Le modestement intitulé Visualizing Quaternions de Hanson [6] analyse les quaternions en utilisant des outils de plusieurs disciplines différentes (Géométrie Riemannienne, nombres complexes, algèbre de Lie, repères mobiles) et est parsemé d’intéressantes anecdotes mathématiques et d’ingénierie ; il discute également de la façon de visualiser les quaternions. Une présentation plus courte sur la visualisation des quaternions est donnée par Hart et al. [7].

8.6Comparaison des méthodes

Passons en revue les découvertes les plus importantes des sections précédentes. Le Tableau 8.1 résume les différences entre les trois méthodes de représentation.

Tableau 8.1Comparaison des matrices, angles d’Euler, cartes exponentielles et quaternions

Certaines situations sont mieux adaptées à un format d’orientation ou à un autre. Les conseils suivants devraient vous aider à sélectionner le meilleur format :

8.7Conversion entre les représentations

Nous avons établi que différentes méthodes de représentation de l’orientation sont appropriées dans différentes situations, et avons également fourni quelques lignes directrices pour choisir la méthode la plus appropriée. Cette section traite de la façon de convertir un déplacement angulaire d’un format à un autre. Elle est divisée en six sous-sections :

Pour plus d’informations sur la conversion entre les formes de représentation, voir l’article de James Diebel [3].

8.7.1Conversion des angles d’Euler en matrice

Les angles d’Euler définissent une séquence de trois rotations. Chacune de ces trois rotations est une rotation simple autour d’un axe cardinal, donc chacune est facile à convertir individuellement en forme matricielle. Nous pouvons calculer la matrice qui définit le déplacement angulaire total en concaténant les matrices pour chaque rotation individuelle. Cet exercice est effectué dans de nombreux livres et sites web. Si vous avez déjà essayé d’utiliser l’une de ces références, vous vous êtes peut-être demandé : « Exactement que se passe-t-il si je multiplie un vecteur par cette matrice ? » La raison de votre confusion est qu’ils ont oublié de mentionner si la matrice effectue la rotation de l’espace objet vers l’espace droit ou de l’espace droit vers l’espace objet. En d’autres termes, il y a en réalité deux matrices différentes, pas seulement une. (Bien sûr, ce sont les transposées l’une de l’autre, donc, en un sens, il n’y a vraiment qu’une seule matrice.) Cette section montre comment calculer les deux.

Certains lecteurs16 pourraient penser que nous insistons trop sur le sujet. Vous avez peut-être compris comment utiliser cette matrice de rotation de ce livre ou site web, et maintenant c’est totalement évident pour vous. Mais nous avons vu cela constituer un obstacle pour trop de programmeurs, donc nous avons choisi d’insister sur ce point. Un exemple courant illustrera la confusion que nous avons observée.

Considérons une situation en temps réel typique avec des objets en mouvement. Supposons que l’orientation de chaque objet est maintenue au format angle d’Euler comme variable d’état. L’un de ces objets est la caméra, et naturellement nous utilisons le même système d’angles d’Euler pour décrire l’orientation de la caméra que pour tout autre objet. Maintenant, à un certain moment, nous aurons besoin de communiquer ces référentiels à l’API graphique. C’est là que la confusion se produit : la matrice que nous utilisons pour décrire l’orientation des objets n’est pas la même matrice que nous utilisons pour décrire l’orientation de la caméra ! L’API graphique nécessite deux types de matrices. (Nous les discuterons plus en détail à la Section 10.3.1.) La transformation de modèle est une matrice qui transforme les vecteurs de l’espace objet vers l’espace monde. La transformation de vue transforme les vecteurs de l’espace monde vers l’espace objet de la caméra. La partie rotation de la matrice de transformation de modèle est une matrice objet-vers-droit, mais la partie rotation de la matrice de transformation de vue est une matrice droit-vers-objet. Ainsi, parler de la matrice de rotation d’Euler omet quelques détails pratiques importants.

Maintenant, dérivons les matrices. Nous commençons par dériver la matrice objet-vers-droit qui effectue la rotation des points de l’espace objet vers l’espace droit. Nous utiliserons les matrices de rotation simple développées à la Section 5.1.2, et celles-ci ont été développées en utilisant la perspective de la transformation active (voir Section 3.3.1 si vous ne vous souvenez pas de la différence entre les transformations actives et passives). Ainsi, pour visualiser la tâche à accomplir, imaginez un point arbitraire sur notre objet. L’objet commence dans l’orientation « identité », et les coordonnées du corps pour notre point, que nous connaissons, sont également les coordonnées droites en ce moment car les deux espaces sont alignés. Nous effectuons la séquence de rotations d’Euler sur l’objet, et le point se déplace dans l’espace jusqu’à ce que, après la troisième rotation, l’objet soit arrivé dans l’orientation décrite par les angles d’Euler. Pendant tout ce temps, notre espace de coordonnées droit utilisé pour mesurer les coordonnées reste fixe. Donc le résultat final de ces calculs est les coordonnées droites pour le point dans son orientation arbitraire.

Il y a un dernier point à noter. Les matrices de rotation élémentaires que nous souhaitons utiliser comme blocs de construction effectuent chacune une rotation autour d’un axe cardinal. Avec les angles d’Euler, les axes de rotation sont les axes du corps, qui (après la première rotation) seront orientés de manière arbitraire. Donc au lieu de faire les rotations d’Euler autour des axes du corps, nous effectuons des rotations à axes fixes, où les rotations se font autour des axes droits. Cela signifie que nous effectuons en réalité les rotations dans l’ordre inverse : d’abord le roulis, puis le tangage, et enfin le cap. Voir la Section 8.3.2 si vous ne vous souvenez pas de ce que sont les rotations à axes fixes.

En résumé, la génération de la matrice de rotation objet-vers-droit est une concaténation simple de trois matrices de rotation simples,

𝐌𝑜bjetdroit=𝐁𝐏𝐇,\mathbf{M}_{\mathit{o}bjet \rightarrow droit} = \mathbf{B}\mathbf{P}\mathbf{H},

𝐁\mathbf{B} , 𝐏\mathbf{P} et 𝐇\mathbf{H} sont les matrices de rotation pour le roulis, le tangage et le cap, qui effectuent des rotations autour des axes zz -, xx - et yy -, respectivement. Nous avons appris à calculer ces matrices de rotation élémentaires à la Section 5.1.2.

Matrices de rotation élémentaires pour le roulis, le tangage et le cap

𝐁=𝐑z(b)=[cosbsinb0sinbcosb0001],𝐏=𝐑x(p)=[1000cospsinp0sinpcosp],𝐇=𝐑y(h)=[cosh0sinh010sinh0cosh].\begin{matrix} {\mathbf{B} = \mathbf{R}_{z}(b)} & {= \begin{bmatrix} {\cos b} & {\sin b} & 0 \\ {- \sin b} & {\cos b} & 0 \\ 0 & 0 & 1 \\ \end{bmatrix},} \\ {\mathbf{P} = \mathbf{R}_{x}(p)} & {= \begin{bmatrix} 1 & 0 & 0 \\ 0 & {\cos p} & {\sin p} \\ 0 & {- \sin p} & {\cos p} \\ \end{bmatrix},} \\ {\mathbf{H} = \mathbf{R}_{y}(h)} & {= \begin{bmatrix} {\cos h} & 0 & {- \sin h} \\ 0 & 1 & 0 \\ {\sin h} & 0 & {\cos h} \\ \end{bmatrix}.} \\ \end{matrix}

En assemblant le tout (et en omettant les calculs fastidieux des multiplications matricielles), nous obtenons

Matrice de rotation objet-vers-droit à partir des angles d’Euler

𝐌𝑜bjetdroit=𝐁𝐏𝐇=[chcb+shspsbsbcpshcb+chspsbchsb+shspcbcbcpsbsh+chspcbshcpspchcp],\begin{matrix} \begin{matrix} \mathbf{M}_{\mathit{o}bjet \rightarrow droit} & {= \mathbf{B}\mathbf{P}\mathbf{H}} \\ & {= \left\lbrack \ \begin{matrix} {ch\, cb + sh\, sp\, sb} & {sb\, cp} & {- sh\, cb + ch\, sp\, sb} \\ {- ch\, sb + sh\, sp\, cb} & {cb\, cp} & {sb\, sh + ch\, sp\, cb} \\ {sh\, cp} & {- sp} & {ch\, cp} \\ \end{matrix} \right\rbrack,} \\ \end{matrix} \\ \end{matrix}

où nous avons introduit la notation abrégée

ch=cosh,cp=cosp,cb=cosb,sh=sinh,sp=sinp,sb=sinb.\begin{matrix} {ch} & {= \cos h,} & {cp} & {= \cos p,} & {cb} & {= \cos b,} \\ {sh} & {= \sin h,} & {sp} & {= \sin p,} & {sb} & {= \sin b.} \\ \end{matrix}

Pour effectuer la rotation des vecteurs de l’espace droit vers l’espace objet, nous utiliserons l’inverse de cette matrice objet-vers-droit. Nous savons que comme une matrice de rotation est orthogonale, l’inverse est simplement la transposée. Cependant, vérifions cela.

Pour visualiser la transformation droit-vers-objet, imaginons annuler les rotations à axes fixes. Nous annulons d’abord le cap, puis le tangage, et enfin le roulis. Comme auparavant, l’objet (et ses points) se déplacent dans l’espace, et nous utilisons les coordonnées droites pour tout mesurer. La seule différence est que cette fois nous partons des coordonnées droites. À la fin de ces rotations, les axes du corps de l’objet sont alignés avec les axes droits, et les coordonnées résultantes sont les coordonnées de l’espace objet :

Matrice de rotation droit-vers-objet à partir des angles d’Euler

𝐌𝑑roitobjet=𝐇1𝐏1𝐁1=𝐑y(h)𝐑x(p)𝐑z(b)=[chcb+shspsbchsb+shspcbshcpsbcpcbcpspshcb+chspsbsbsh+chspcbchcp].\begin{matrix} \begin{matrix} \mathbf{M}_{\mathit{d}roit \rightarrow objet} & {= \mathbf{H}^{- 1}\mathbf{P}^{- 1}\mathbf{B}^{- 1} = \mathbf{R}_{y}( - h)\,\,\mathbf{R}_{x}( - p)\,\,\mathbf{R}_{z}( - b)} \\ & {= \left\lbrack \ \begin{matrix} {ch\, cb + sh\, sp\, sb} & {- ch\, sb + sh\, sp\, cb} & {sh\, cp} \\ {sb\, cp} & {cb\, cp} & {- sp} \\ {- sh\, cb + ch\, sp\, sb} & {sb\, sh + ch\, sp\, cb} & {ch\, cp} \\ \end{matrix} \right\rbrack.} \\ \end{matrix} \\ \end{matrix}

En comparant les Équations (8.14) et (8.15), nous voyons que la matrice objet-vers-droit est bien la transposée de la matrice droit-vers-objet, comme prévu.

Notez également que nous pouvons considérer les matrices de rotation 𝐇1\mathbf{H}^{- 1} , 𝐏1\mathbf{P}^{- 1} et 𝐁1\mathbf{B}^{- 1} soit comme les inverses de leurs homologues, soit comme des matrices de rotation ordinaires utilisant les angles de rotation opposés.

8.7.2Conversion d’une matrice en angles d’Euler

La conversion d’un déplacement angulaire de la forme matricielle en représentation par angles d’Euler implique plusieurs considérations :

En gardant ces considérations à l’esprit, nous cherchons à résoudre les angles d’Euler à partir de la matrice de rotation (Équation (8.14)) directement. Pour votre commodité, la matrice est développée ci-dessous :

[coshcosb+sinhsinpsinbsinbcospsinhcosb+coshsinpsinbcoshsinb+sinhsinpcosbcosbcospsinbsinh+coshsinpcosbsinhcospsinpcoshcosp].\begin{bmatrix} {\cos h\cos b + \sin h\sin p\sin b} & {\sin b\cos p} & {- \sin h\cos b + \cos h\sin p\sin b} \\ {- \cos h\sin b + \sin h\sin p\cos b} & {\cos b\cos p} & {\sin b\sin h + \cos h\sin p\cos b} \\ {\sin h\cos p} & {- \sin p} & {\cos h\cos p} \\ \end{bmatrix}.

Nous pouvons résoudre pp immédiatement à partir de m32m_{32} :

m32=sinp,m32=sinp,arcsin(m32)=p.\begin{matrix} m_{32} & {= - \sin p,} \\ {- m_{32}} & {= \sin p,} \\ {\arcsin( - m_{32})} & {= p.} \\ \end{matrix}

La fonction de la bibliothèque standard C asin() retourne une valeur dans la plage [π/2,+π/2]\lbrack - \pi/2,{+ \pi}/2\rbrack radians, ce qui correspond à [90o,+90o]\lbrack - 90^{o},{+ 90^{o}}\rbrack , exactement la plage de valeurs pour le tangage autorisées dans l’ensemble canonique.

Maintenant que nous connaissons pp , nous connaissons aussi cosp\cos p . Supposons d’abord que cosp0\cos p \neq 0 . Puisque 90op+90o- 90^{o} \leq p \leq + 90^{o} , cela signifie que cosp>0\cos p > 0 . Nous pouvons déterminer sinh\sin h et cosh\cos h en divisant m13m_{13} et m33m_{33} par cosp\cos p :

m31=sinhcosp,m33=coshcosp,m31/cosp=sinh,m33/cosp=cosh.\begin{matrix} m_{31} & {= \sin h\cos p,} & m_{33} & {= \cos h\cos p,} \\ {m_{31}/\cos p} & {= \sin h,} & {m_{33}/\cos p} & {= \cos h.} \\ \end{matrix}

Une fois que nous connaissons le sinus et le cosinus d’un angle, nous pouvons calculer la valeur de l’angle avec la fonction de la bibliothèque standard C atan2(). Cette fonction retourne un angle dans la plage [π,+π]\lbrack - \pi,{+ \pi}\rbrack radians ( [180o,+180o]\lbrack - 180^{o},{+ 180^{o}}\rbrack ), qui est de nouveau notre plage de sortie souhaitée. Connaître seulement le sinus ou le cosinus d’un angle n’est pas suffisant pour identifier de manière unique un angle pouvant prendre n’importe quelle valeur dans cette plage, c’est pourquoi nous ne pouvons pas simplement utiliser asin() ou acos().

En substituant les résultats de l’Équation (8.16), nous obtenons

h=atan2(sinh,cosh)=atan2(m31/cosp,m33/cosp).h = {atan2}(\sin h,\cos h) = {atan2}(m_{31}/\cos p,m_{33}/\cos p).

Cependant, nous pouvons en fait simplifier cela car atan2(y,x) fonctionne en calculant l’arctangente du quotient y/xy/x , en utilisant les signes des deux arguments pour placer l’angle dans le bon quadrant. Comme cosp>0\cos p > 0 , les divisions n’affectent pas les signes de xx ou yy , et ne changent pas non plus le quotient y/xy/x . En omettant les divisions inutiles par cosp\cos p , le cap peut être calculé plus simplement par

h=atan2(m31,m33).h = {atan2}(m_{31},m_{33}).

Le roulis est calculé de manière similaire à partir de m12m_{12} et m22m_{22} :

m12=sinbcosp,m12/cosp=sinb;m22=cosbcosp,m22/cosp=cosb;b=atan2(sinb,cosb)=atan2(m12/cosp,m22/cosp)=atan2(m12,m22).\begin{matrix} m_{12} & {= \sin b\cos p,} \\ {m_{12}/\cos p} & {= \sin b;} \\ m_{22} & {= \cos b\cos p,} \\ {m_{22}/\cos p} & {= \cos b;} \\ b & {= {atan2}(\sin b,\cos b) = {atan2}(m_{12}/\cos p,m_{22}/\cos p)} \\ & {= {atan2}(m_{12},m_{22}).} \\ \end{matrix}

Nous avons maintenant les trois angles. Cependant, si cosp=0\cos p = 0 , alors nous ne pouvons pas utiliser l’astuce ci-dessus car cela entraînerait une division par zéro. Mais notez que lorsque cosp=0\cos p = 0 , alors p=±90op = \pm 90^{o} , ce qui signifie que nous regardons directement vers le haut ou vers le bas. C’est la situation de blocage de Cardan, où le cap et le roulis effectuent en fait une rotation autour du même axe physique (l’axe vertical). En d’autres termes, les singularités mathématiques et géométriques se produisent en même temps. Dans ce cas, nous attribuerons arbitrairement toute la rotation autour de l’axe vertical au cap, et fixerons le roulis à zéro. Cela signifie que nous connaissons les valeurs de tangage et de roulis, et il ne nous reste plus qu’à résoudre pour le cap. Si nous faisons les hypothèses simplificatrices

cosp=0,b=0,sinb=0,cosb=1,\begin{matrix} {\cos p = 0,} & & {b = 0,} & & {\sin b = 0,} & & {\cos b = 1,} \\ \end{matrix}

et que nous substituons ces hypothèses dans l’Équation (8.14), nous obtenons

[coshcosb+sinhsinpsinbsinbcospsinhcosb+coshsinpsinbcoshsinb+sinhsinpcosbcosbcospsinbsinh+coshsinpcosbsinhcospsinpcoshcosp]\begin{matrix} {\!\begin{bmatrix} {\cos h\cos b + \sin h\sin p\sin b} & {\sin b\cos p} & {- \sin h\cos b + \cos h\sin p\sin b} \\ {- \cos h\sin b + \sin h\sin p\cos b} & {\cos b\cos p} & {\sin b\sin h + \cos h\sin p\cos b} \\ {\sin h\cos p} & {- \sin p} & {\cos h\cos p} \\ \end{bmatrix}} \\ \end{matrix}

=[cosh(1)+sinhsinp(0)(0)(0)sinh(1)+coshsinp(0)cosh(0)+sinhsinp(1)(1)(0)(0)sinh+coshsinp(1)sinh(0)sinpcosh(0)]=[cosh0sinhsinhsinp0coshsinp0sinp0].\begin{matrix} & {= \left\lbrack \ \begin{matrix} {\cos h\,(1) + \sin h\sin p\,(0)} & {(0)(0)} & {- \sin h\,(1) + \cos h\sin p\,(0)} \\ {- \cos h\,(0) + \sin h\sin p\,(1)} & {(1)(0)} & {(0)\sin h + \cos h\sin p\,(1)} \\ {\sin h\,(0)} & {- \sin p} & {\cos h\,(0)} \\ \end{matrix} \right\rbrack} \\ & {= \left\lbrack \ \begin{matrix} {\cos h} & 0 & {- \sin h} \\ {\sin h\sin p} & 0 & {\cos h\sin p} \\ 0 & {- \sin p} & 0 \\ \end{matrix} \right\rbrack.} \\ \end{matrix}

Nous pouvons maintenant calculer hh à partir de m13- m_{13} et m11m_{11} , qui contiennent respectivement le sinus et le cosinus du cap.

Le Listing 8.4 est du code C qui extrait les angles d’Euler d’une matrice de rotation objet-vers-droit, en utilisant la technique développée ci-dessus.

// Supposer que la matrice est stockée dans ces variables :
float m11,m12,m13;
float m21,m22,m23;
float m31,m32,m33;

// Nous calculerons les valeurs des angles d'Euler en radians
// et les stockerons ici :
float h,p,b;

// Extraire le tangage de m32, en faisant attention aux erreurs de domaine avec
// asin(). Nous pourrions avoir des valeurs légèrement hors plage en raison de
// l'arithmétique en virgule flottante.
float sp = -m32;
if (sp <= -1.0f) {
    p = -1.570796f; // -pi/2
} else if (sp >= 1.0f) {
    p = 1.570796f; // pi/2
} else {
    p = asin(sp);
}

// Vérifier le cas de blocage de Cardan, avec une légère tolérance
// pour l'imprécision numérique
if (fabs(sp) > 0.9999f) {

    // Nous regardons directement vers le haut ou vers le bas.
    // Forcer le roulis à zéro et simplement définir le cap
    b = 0.0f;
    h = atan2(-m13, m11);

} else {

    // Calculer le cap à partir de m13 et m33
    h = atan2(m31, m33);

    // Calculer le roulis à partir de m21 et m22
    b = atan2(m12, m22);
}

8.7.3Conversion d’un quaternion en matrice

Nous avons quelques options pour convertir un quaternion en matrice de rotation. La façon la plus courante est de développer la multiplication de quaternions 𝐪𝐯𝐪1\mathbf{q}\mathbf{v}\mathbf{q}^{- 1} . Cela produit la matrice correcte, mais nous n’avons aucune vraie certitude quant à la raison pour laquelle la matrice est correcte. (Nous acquérons cependant une certaine expérience dans la manipulation des quaternions ; voir Exercice 10.) Nous choisissons une autre option et nous en tenons purement à l’interprétation géométrique des composantes du quaternion. Puisqu’un quaternion est essentiellement une version encodée d’une rotation axe-angle, nous essayons de construire la matrice à partir de Section 5.1.3, qui effectue une rotation autour d’un axe arbitraire :

[nx2(1cosθ)+cosθnxny(1cosθ)+nzsinθnxnz(1cosθ)nysinθnxny(1cosθ)nzsinθny2(1cosθ)+cosθnynz(1cosθ)+nxsinθnxnz(1cosθ)+nysinθnynz(1cosθ)nxsinθnz2(1cosθ)+cosθ].\begin{bmatrix} {{n_{x}}^{2}\left( 1 - \cos\theta \right) + \cos\theta} & {n_{x}n_{y}\left( 1 - \cos\theta \right) + n_{z}\sin\theta} & {n_{x}n_{z}\left( 1 - \cos\theta \right) - n_{y}\sin\theta} \\ {n_{x}n_{y}\left( 1 - \cos\theta \right) - n_{z}\sin\theta} & {{n_{y}}^{2}\left( 1 - \cos\theta \right) + \cos\theta} & {n_{y}n_{z}\left( 1 - \cos\theta \right) + n_{x}\sin\theta} \\ {n_{x}n_{z}\left( 1 - \cos\theta \right) + n_{y}\sin\theta} & {n_{y}n_{z}\left( 1 - \cos\theta \right) - n_{x}\sin\theta} & {{n_{z}}^{2}\left( 1 - \cos\theta \right) + \cos\theta} \\ \end{bmatrix}.

Malheureusement, cette matrice est exprimée en termes de 𝐧̂\hat{\mathbf{n}} et θ\theta , mais les composantes d’un quaternion sont

w=cos(θ/2),x=nxsin(θ/2),y=nysin(θ/2),z=nzsin(θ/2).\begin{matrix} w & {= \cos(\theta/2),} \\ x & {= n_{x}\sin(\theta/2),} \\ y & {= n_{y}\sin(\theta/2),} \\ z & {= n_{z}\sin(\theta/2).} \\ \end{matrix}

Voyons si nous pouvons manipuler la matrice pour obtenir une forme où nous pouvons substituer ww , xx , yy et zz . Nous devons faire cela pour les neuf éléments de la matrice. Heureusement, la matrice a beaucoup de structure, et il n’y a vraiment que deux cas principaux à traiter : les éléments diagonaux, et les éléments non diagonaux.

Cette dérivation est délicate, et il n’est pas nécessaire de comprendre comment la matrice est dérivée pour utiliser la matrice. Si vous n’êtes pas intéressé par les mathématiques, passez à l’Équation (8.20).

Commençons par les éléments diagonaux de la matrice. Nous travaillons m11m_{11} ici ; m22m_{22} et m33m_{33} peuvent être résolus de manière similaire :

m11=nx2(1cosθ)+cosθ.\begin{matrix} {m_{11} = {n_{x}}^{2}\left( 1 - \cos\theta \right) + \cos\theta.} \\ \end{matrix}

Nous effectuons d’abord quelques manipulations qui peuvent sembler être un détour. Le but de ces étapes deviendra apparent dans un instant :

m11=nx2(1cosθ)+cosθ=nx2nx2cosθ+cosθ=11+nx2nx2cosθ+cosθ=1(1nx2+nx2cosθcosθ)=1(1cosθnx2+nx2cosθ)=1(1nx2)(1cosθ).\begin{matrix} m_{11} & {= {n_{x}}^{2}\left( 1 - \cos\theta \right) + \cos\theta} \\ & {= {n_{x}}^{2} - {n_{x}}^{2}\cos\theta + \cos\theta} \\ & {= 1 - 1 + {n_{x}}^{2} - {n_{x}}^{2}\cos\theta + \cos\theta} \\ & {= 1 - (1 - {n_{x}}^{2} + {n_{x}}^{2}\cos\theta - \cos\theta)} \\ & {= 1 - (1 - \cos\theta - {n_{x}}^{2} + {n_{x}}^{2}\cos\theta)} \\ & {= 1 - (1 - {n_{x}}^{2})(1 - \cos\theta).} \\ \end{matrix}

Maintenant, nous devons éliminer le terme cosθ\cos\theta ; et nous voudrions le remplacer par quelque chose qui contient cosθ/2\cos\theta/2 ou sinθ/2\sin\theta/2 , puisque les composantes d’un quaternion contiennent ces termes. Comme nous l’avons fait auparavant, posons α=θ/2\alpha = \theta/2 . Nous écrivons l’une des formules de l’angle double pour le cosinus de la Section 1.4.5 en termes de α\alpha , puis nous substituons θ\theta :

cos2α=12sin2α,cosθ=12sin2(θ/2).\begin{matrix} {\cos 2\alpha} & {= 1 - 2\sin^{2}\alpha,} \\ {\cos\theta} & {= 1 - 2\sin^{2}(\theta/2).} \\ \end{matrix}

En substituant cosθ\cos\theta dans l’Équation (8.17), nous obtenons

m11=1(1nx2)(1cosθ)=1(1nx2)(1(12sin2(θ/2)))=1(1nx2)(2sin2(θ/2)).\begin{matrix} m_{11} & {= 1 - (1 - {n_{x}}^{2})(1 - \cos\theta)} \\ & {= 1 - (1 - {n_{x}}^{2})\left( 1 - \left( 1 - 2\sin^{2}(\theta/2) \right) \right)} \\ & {= 1 - (1 - {n_{x}}^{2})\left( 2\sin^{2}(\theta/2) \right).} \\ \end{matrix}

Maintenant, nous utilisons le fait que puisque 𝐧̂\hat{\mathbf{n}} est un vecteur unitaire, nx2+ny2+nz2=1{n_{x}}^{2} + {n_{y}}^{2} + {n_{z}}^{2} = 1 , et donc 1nx2=ny2+nz21 - {n_{x}}^{2} = {n_{y}}^{2} + {n_{z}}^{2} :

m11=1(1nx2)(2sin2(θ/2))=1(ny2+nz2)(2sin2(θ/2))=12ny2sin2(θ/2)2nz2sin2(θ/2)=12y22z2.\begin{matrix} m_{11} & {= 1 - (1 - {n_{x}}^{2})\left( 2\sin^{2}(\theta/2) \right)} \\ & {= 1 - ({n_{y}}^{2} + {n_{z}}^{2})\left( 2\sin^{2}(\theta/2) \right)} \\ & {= 1 - 2{n_{y}}^{2}\sin^{2}(\theta/2) - 2{n_{z}}^{2}\sin^{2}(\theta/2)} \\ & {= 1 - 2y^{2} - 2z^{2}.} \\ \end{matrix}

Les éléments m22m_{22} et m33m_{33} sont dérivés de manière similaire. Les résultats sont présentés à la fin de cette section lorsque nous donnons la matrice complète à l’Équation (8.20).

Examinons maintenant les éléments non diagonaux de la matrice ; ils sont plus faciles que les éléments diagonaux. Nous utilisons m12m_{12} comme exemple :

m12=nxny(1cosθ)+nzsinθ.\begin{matrix} {m_{12} = n_{x}n_{y}\left( 1 - \cos\theta \right) + n_{z}\sin\theta.} \\ \end{matrix}

Nous utilisons l’inverse de la formule de l’angle double pour le sinus (voir la Section 1.4.5) :

sin2α=2sinαcosα,sinθ=2sin(θ/2)cos(θ/2).\begin{matrix} {\sin 2\alpha} & {= 2\sin\alpha\cos\alpha,} \\ {\sin\theta} & {= 2\sin(\theta/2)\cos(\theta/2).} \\ \end{matrix}

Maintenant, nous substituons les Équations (8.17) et (8.19) dans l’Équation (8.18) et simplifions :

m12=nxny(1cosθ)+nzsinθ=nxny(1(12sin2(θ/2)))+nz(2sin(θ/2)cos(θ/2))=nxny(2sin2(θ/2))+2nzsin(θ/2)cos(θ/2)=2(nxsin(θ/2))(nysin(θ/2))+2cos(θ/2)(nzsin(θ/2))=2xy+2wz.\begin{matrix} m_{12} & {= n_{x}n_{y}\left( 1 - \cos\theta \right) + n_{z}\sin\theta} \\ & {= n_{x}n_{y}\left( 1 - \left( 1 - 2\sin^{2}(\theta/2) \right) \right) + n_{z}\left( 2\sin(\theta/2)\cos(\theta/2) \right)} \\ & {= n_{x}n_{y}\left( 2\sin^{2}(\theta/2) \right) + 2n_{z}\sin(\theta/2)\cos(\theta/2)} \\ & {= 2\left( n_{x}\sin(\theta/2) \right)\left( n_{y}\sin(\theta/2) \right) + 2\cos(\theta/2)\left( n_{z}\sin(\theta/2) \right)} \\ & {= 2xy + 2wz.} \\ \end{matrix}

Les autres éléments non diagonaux sont dérivés de manière similaire.

Enfin, nous présentons la matrice de rotation complète construite à partir d’un quaternion :

Conversion d’un quaternion en matrice de rotation 3×33 \times 3

[12y22z22xy+2wz2xz2wy2xy2wz12x22z22yz+2wx2xz+2wy2yz2wx12x22y2].\begin{matrix} {\begin{bmatrix} {1 - 2y^{2} - 2z^{2}} & {2xy + 2wz} & {2xz - 2wy} \\ {2xy - 2wz} & {1 - 2x^{2} - 2z^{2}} & {2yz + 2wx} \\ {2xz + 2wy} & {2yz - 2wx} & {1 - 2x^{2} - 2y^{2}} \\ \end{bmatrix}.} \\ \end{matrix}

D’autres variantes peuvent être trouvées dans d’autres sources.17 Par exemple, m11=1+2w2+2z2m_{11} = - 1 + 2w^{2} + 2z^{2} fonctionne également, car w2+x2+y2+z2=1w^{2} + x^{2} + y^{2} + z^{2} = 1 . En hommage à Shoemake, qui a porté les quaternions à l’attention de la communauté d’infographie, nous avons adapté notre dérivation pour produire la version de sa source précoce et faisant autorité [11].

8.7.4Conversion d’une matrice en quaternion

Pour extraire un quaternion de la matrice de rotation correspondante, nous faisons de l’ingénierie inverse sur l’Équation (8.20). En examinant la somme des éléments diagonaux (connue sous le nom de trace de la matrice), nous obtenons

tr(𝐌)=m11+m22+m33=(12y22z2)+(12x22z2)+(12x22y2)=34(x2+y2+z2)=34(1w2)=4w21,\begin{matrix} {{tr}(\mathbf{M})} & {= m_{11} + m_{22} + m_{33}} \\ & {= (1 - 2y^{2} - 2z^{2}) + (1 - 2x^{2} - 2z^{2}) + (1 - 2x^{2} - 2y^{2})} \\ & {= 3 - 4(x^{2} + y^{2} + z^{2})} \\ & {= 3 - 4(1 - w^{2})} \\ & {= 4w^{2} - 1,} \\ \end{matrix}

et donc nous pouvons calculer ww par

w=m11+m22+m33+12.\begin{matrix} {w = \frac{\sqrt{m_{11} + m_{22} + m_{33} + 1}}{2}.} \\ \end{matrix}

Les trois autres éléments peuvent être calculés de manière similaire, en niant deux des trois éléments de la trace :

m11m22m33=(12y22z2)(12x22z2)(12x22y2)=4x21,m11+m22m33=(12y22z2)+(12x22z2)(12x22y2)=4y21,\begin{matrix} {m_{11} - m_{22} - m_{33}} & {= (1 - 2y^{2} - 2z^{2}) - (1 - 2x^{2} - 2z^{2}) - (1 - 2x^{2} - 2y^{2})} \\ & {= 4x^{2} - 1,} \\ {- m_{11} + m_{22} - m_{33}} & {= - (1 - 2y^{2} - 2z^{2}) + (1 - 2x^{2} - 2z^{2}) - (1 - 2x^{2} - 2y^{2})} \\ & {= 4y^{2} - 1,} \\ \end{matrix}

m11m22+m33=(12y22z2)(12x22z2)+(12x22y2)=4z21,x=m11m22m33+12,y=m11+m22m33+12,z=m11m22+m33+12.\begin{matrix} {- m_{11} - m_{22} + m_{33}} & {= - (1 - 2y^{2} - 2z^{2}) - (1 - 2x^{2} - 2z^{2}) + (1 - 2x^{2} - 2y^{2})} \\ & {= 4z^{2} - 1,} \\ x & {= \frac{\sqrt{m_{11} - m_{22} - m_{33} + 1}}{2},} \\ y & {= \frac{\sqrt{- m_{11} + m_{22} - m_{33} + 1}}{2},} \\ z & {= \frac{\sqrt{- m_{11} - m_{22} + m_{33} + 1}}{2}.} \\ \end{matrix}

Malheureusement, nous ne pouvons pas utiliser cette astuce pour les quatre composantes, car la racine carrée donnera toujours des résultats positifs. (Plus précisément, nous n’avons aucune base pour choisir la racine positive ou négative.) Cependant, puisque 𝐪\mathbf{q} et 𝐪- \mathbf{q} représentent la même orientation, nous pouvons arbitrairement choisir d’utiliser la racine non négative pour l’une des quatre composantes et retourner toujours un quaternion correct. Nous ne pouvons tout simplement pas utiliser la technique ci-dessus pour les quatre valeurs du quaternion.

Une autre approche consiste à examiner la somme et la différence des éléments matriciels diagonalement opposés :

m12+m21=(2xy+2wz)+(2xy2wz)=4xy,m12m21=(2xy+2wz)(2xy2wz)=4wz,m31+m13=(2xz+2wy)+(2xz2wy)=4xz,m31m13=(2xz+2wy)(2xz2wy)=4wy,m23+m32=(2yz+2wx)+(2yz2wx)=4yz,m23m32=(2yz+2wx)(2yz2wx)=4wx.\begin{matrix} {m_{12} + m_{21}} & {= (2xy + 2wz) + (2xy - 2wz) = 4xy,} \\ {m_{12} - m_{21}} & {= (2xy + 2wz) - (2xy - 2wz) = 4wz,} \\ {m_{31} + m_{13}} & {= (2xz + 2wy) + (2xz - 2wy) = 4xz,} \\ {m_{31} - m_{13}} & {= (2xz + 2wy) - (2xz - 2wy) = 4wy,} \\ {m_{23} + m_{32}} & {= (2yz + 2wx) + (2yz - 2wx) = 4yz,} \\ {m_{23} - m_{32}} & {= (2yz + 2wx) - (2yz - 2wx) = 4wx.} \\ \end{matrix}

Armés de ces formules, nous développons une stratégie en deux étapes. Nous résolvons d’abord l’une des composantes à partir de la trace, en utilisant l’une des Équations (8.21)(8.26). Ensuite, nous substituons cette valeur connue dans les Équations (8.27)(8.32) pour résoudre les trois autres. Essentiellement, cette stratégie se résume à sélectionner une ligne du Tableau 8.2 et ensuite résoudre les équations dans cette ligne de gauche à droite.

w=m11+m22+m33+12x=m23m324wy=m31m134wz=m12m214wx=m11m22m33+12w=m23m324xy=m12+m214xz=m31+m134xy=m11+m22m33+12w=m31m134yx=m12+m214yz=m23+m324yz=m11m22+m33+12w=m12m214zx=m31+m134zy=m23+m324z\begin{matrix} {w = \frac{\sqrt{m_{11} + m_{22} + m_{33} + 1}}{2}} & \Longrightarrow & {x = \frac{m_{23} - m_{32}}{4w}} & {y = \frac{m_{31} - m_{13}}{4w}} & {z = \frac{m_{12} - m_{21}}{4w}} \\ & & & & \\ {x = \frac{\sqrt{m_{11} - m_{22} - m_{33} + 1}}{2}} & \Longrightarrow & {w = \frac{m_{23} - m_{32}}{4x}} & {y = \frac{m_{12} + m_{21}}{4x}} & {z = \frac{m_{31} + m_{13}}{4x}} \\ & & & & \\ {y = \frac{\sqrt{- m_{11} + m_{22} - m_{33} + 1}}{2}} & \Longrightarrow & {w = \frac{m_{31} - m_{13}}{4y}} & {x = \frac{m_{12} + m_{21}}{4y}} & {z = \frac{m_{23} + m_{32}}{4y}} \\ & & & & \\ {z = \frac{\sqrt{- m_{11} - m_{22} + m_{33} + 1}}{2}} & \Longrightarrow & {w = \frac{m_{12} - m_{21}}{4z}} & {x = \frac{m_{31} + m_{13}}{4z}} & {y = \frac{m_{23} + m_{32}}{4z}} \\ \end{matrix}

Tableau 8.2Extraction d’un quaternion à partir d’une matrice de rotation

La seule question est : « Quelle ligne devrions-nous utiliser ? » En d’autres termes, quelle composante devrions-nous résoudre en premier ? La stratégie la plus simple serait de simplement en choisir une arbitrairement et toujours utiliser la même procédure, mais ce n’est pas bon. Disons que nous choisissons de toujours utiliser la première ligne, ce qui signifie que nous résolvons ww à partir de la trace, puis xx , yy et zz avec les équations du côté droit de la flèche. Mais si w=0w = 0 , les divisions à suivre seront indéfinies. Même si w>0w > 0 , un petit ww produira une instabilité numérique. Shoemake [11] suggère la stratégie de déterminer d’abord laquelle parmi ww , xx , yy et zz a la plus grande valeur absolue (ce que nous pouvons faire sans effectuer de racines carrées), de calculer cette composante en utilisant la diagonale de la matrice, et ensuite de l’utiliser pour calculer les trois autres selon le Tableau 8.2.

Le Listing 8.5 implémente cette stratégie de manière directe.

// Matrice d'entrée :
float m11,m12,m13;
float m21,m22,m23;
float m31,m32,m33;

// Quaternion de sortie
float w,x,y,z;

// Déterminer laquelle parmi w, x, y, z a la plus grande valeur absolue
float fourWSquaredMinus1 = m11 + m22 + m33;
float fourXSquaredMinus1 = m11 - m22 - m33;
float fourYSquaredMinus1 = m22 - m11 - m33;
float fourZSquaredMinus1 = m33 - m11 - m22;

int biggestIndex = 0;
float fourBiggestSquaredMinus1 = fourWSquaredMinus1;
if (fourXSquaredMinus1 > fourBiggestSquaredMinus1) {
    fourBiggestSquaredMinus1 = fourXSquaredMinus1;
    biggestIndex = 1;
}
if (fourYSquaredMinus1 > fourBiggestSquaredMinus1) {
    fourBiggestSquaredMinus1 = fourYSquaredMinus1;
    biggestIndex = 2;
}
if (fourZSquaredMinus1 > fourBiggestSquaredMinus1) {
    fourBiggestSquaredMinus1 = fourZSquaredMinus1;
    biggestIndex = 3;
}

// Effectuer la racine carrée et la division
float biggestVal = sqrt(fourBiggestSquaredMinus1 + 1.0f) * 0.5f;
float mult = 0.25f / biggestVal;

// Appliquer le tableau pour calculer les valeurs du quaternion
switch (biggestIndex) {
    case 0:
        w = biggestVal;
        x = (m23 - m32) * mult;
        y = (m31 - m13) * mult;
        z = (m12 - m21) * mult;
        break;

    case 1:
        x = biggestVal;
        w = (m23 - m32) * mult;
        y = (m12 + m21) * mult;
        z = (m31 + m13) * mult;
        break;

    case 2:
        y = biggestVal;
        w = (m31 - m13) * mult;
        x = (m12 + m21) * mult;
        z = (m23 + m32) * mult;
        break;

    case 3:
        z = biggestVal;
        w = (m12 - m21) * mult;
        x = (m31 + m13) * mult;
        y = (m23 + m32) * mult;
        break;
}

8.7.5Conversion des angles d’Euler en quaternion

Pour convertir un déplacement angulaire de la forme angle d’Euler en quaternion, nous utilisons une technique similaire à celle utilisée à la Section 8.7.1 pour générer une matrice de rotation à partir des angles d’Euler. Nous convertissons d’abord les trois rotations en format quaternion individuellement, ce qui est une opération triviale. Ensuite, nous concaténons ces trois quaternions dans le bon ordre. Tout comme avec les matrices, il y a deux cas à considérer : l’un lorsque nous souhaitons générer un quaternion objet-vers-droit, et un second lorsque nous voulons le quaternion droit-vers-objet. Comme les deux sont les conjugués l’un de l’autre, nous effectuons la dérivation uniquement pour le quaternion objet-vers-droit.

Comme nous l’avons fait à la Section 8.7.1, nous attribuons les angles d’Euler aux variables hh , pp et bb . Soient 𝐡\mathbf{h} , 𝐩\mathbf{p} et 𝐛\mathbf{b} des quaternions qui effectuent les rotations autour des axes yy , xx et zz , respectivement :

𝐡=[cos(h/2)(0sin(h/2)0)],𝐩=[cos(p/2)(sin(p/2)00)],𝐛=[cos(b/2)(00sin(b/2))].\begin{matrix} \mathbf{h} & {= \begin{bmatrix} {\cos(h/2)} \\ \begin{pmatrix} 0 \\ {\sin(h/2)} \\ 0 \\ \end{pmatrix} \\ \end{bmatrix},} & \mathbf{p} & {= \begin{bmatrix} {\cos(p/2)} \\ \begin{pmatrix} {\sin(p/2)} \\ 0 \\ 0 \\ \end{pmatrix} \\ \end{bmatrix},} & \mathbf{b} & {= \begin{bmatrix} {\cos(b/2)} \\ \begin{pmatrix} 0 \\ 0 \\ {\sin(b/2)} \\ \end{pmatrix} \\ \end{bmatrix}.} \\ \end{matrix}

Maintenant, nous concaténons ces quaternions dans le bon ordre. Nous avons deux sources de « renversement », qui s’annulent mutuellement. Nous utilisons des rotations à axes fixes, donc l’ordre des rotations est en réalité le roulis, puis le tangage, et enfin le cap. Cependant, la multiplication de quaternions effectue les rotations de droite à gauche (voir Section 8.7.1 si vous ne comprenez pas la première source de renversement, et Section 8.5.7 pour la seconde) :

Calcul du quaternion objet-vers-droit à partir d’un ensemble d’angles d’Euler

𝐪𝑜𝑏𝑗𝑒𝑡𝑑𝑟𝑜𝑖𝑡(h,p,b)=𝐡𝐩𝐛=[cos(h/2)(0sin(h/2)0)][cos(p/2)(sin(p/2)00)][cos(b/2)(00sin(b/2))]=[cos(h/2)cos(p/2)(cos(h/2)sin(p/2)sin(h/2)cos(p/2)sin(h/2)sin(p/2))][cos(b/2)(00sin(b/2))]=[cos(h/2)cos(p/2)cos(b/2)+sin(h/2)sin(p/2)sin(b/2)(cos(h/2)sin(p/2)cos(b/2)+sin(h/2)cos(p/2)sin(b/2)sin(h/2)cos(p/2)cos(b/2)cos(h/2)sin(p/2)sin(b/2)cos(h/2)cos(p/2)sin(b/2)sin(h/2)sin(p/2)cos(b/2))].\begin{matrix} & {\mathbf{q}_{\mathit{o}\mathit{b}\mathit{j}\mathit{e}\mathit{t} \rightarrow \mathit{d}\mathit{r}\mathit{o}\mathit{i}\mathit{t}}(h,p,b) = \mathbf{h}\mathbf{p}\mathbf{b}} \\ & {= \begin{bmatrix} {\cos(h/2)} \\ \begin{pmatrix} 0 \\ {\sin(h/2)} \\ 0 \\ \end{pmatrix} \\ \end{bmatrix}\begin{bmatrix} {\cos(p/2)} \\ \begin{pmatrix} {\sin(p/2)} \\ 0 \\ 0 \\ \end{pmatrix} \\ \end{bmatrix}\begin{bmatrix} {\cos(b/2)} \\ \begin{pmatrix} 0 \\ 0 \\ {\sin(b/2)} \\ \end{pmatrix} \\ \end{bmatrix}} \\ & {= \begin{bmatrix} {\cos(h/2)\cos(p/2)} \\ \begin{pmatrix} {\cos(h/2)\sin(p/2)} \\ {\sin(h/2)\cos(p/2)} \\ {- \sin(h/2)\sin(p/2)} \\ \end{pmatrix} \\ \end{bmatrix}\begin{bmatrix} {\cos(b/2)} \\ \begin{pmatrix} 0 \\ 0 \\ {\sin(b/2)} \\ \end{pmatrix} \\ \end{bmatrix}} \\ & {= \begin{bmatrix} {\cos(h/2)\cos(p/2)\cos(b/2) + \sin(h/2)\sin(p/2)\sin(b/2)} \\ \begin{pmatrix} {\cos(h/2)\sin(p/2)\cos(b/2) + \sin(h/2)\cos(p/2)\sin(b/2)} \\ {\sin(h/2)\cos(p/2)\cos(b/2) - \cos(h/2)\sin(p/2)\sin(b/2)} \\ {\cos(h/2)\cos(p/2)\sin(b/2) - \sin(h/2)\sin(p/2)\cos(b/2)} \\ \end{pmatrix} \\ \end{bmatrix}.} \\ \end{matrix}

Le quaternion droit-vers-objet est simplement le conjugué :

Le quaternion droit-vers-objet à partir d’un ensemble d’angles d’Euler

𝐪𝑑𝑟𝑜𝑖𝑡𝑜𝑏𝑗𝑒𝑡(h,p,b)=𝐪𝑜𝑏𝑗𝑒𝑡𝑑𝑟𝑜𝑖𝑡(h,p,b)*=[cos(h/2)cos(p/2)cos(b/2)+sin(h/2)sin(p/2)sin(b/2)(cos(h/2)sin(p/2)cos(b/2)sin(h/2)cos(p/2)sin(b/2)cos(h/2)sin(p/2)sin(b/2)sin(h/2)cos(p/2)cos(b/2)sin(h/2)sin(p/2)cos(b/2)cos(h/2)cos(p/2)sin(b/2))].\begin{matrix} & {\mathbf{q}_{\mathit{d}\mathit{r}\mathit{o}\mathit{i}\mathit{t} \rightarrow \mathit{o}\mathit{b}\mathit{j}\mathit{e}\mathit{t}}(h,p,b) = \mathbf{q}_{\mathit{o}\mathit{b}\mathit{j}\mathit{e}\mathit{t} \rightarrow \mathit{d}\mathit{r}\mathit{o}\mathit{i}\mathit{t}}(h,p,b)^{\ast}} \\ & {= \begin{bmatrix} {\cos(h/2)\cos(p/2)\cos(b/2) + \sin(h/2)\sin(p/2)\sin(b/2)} \\ \begin{pmatrix} {- \cos(h/2)\sin(p/2)\cos(b/2) - \sin(h/2)\cos(p/2)\sin(b/2)} \\ {\cos(h/2)\sin(p/2)\sin(b/2) - \sin(h/2)\cos(p/2)\cos(b/2)} \\ {\sin(h/2)\sin(p/2)\cos(b/2) - \cos(h/2)\cos(p/2)\sin(b/2)} \\ \end{pmatrix} \\ \end{bmatrix}.} \\ \end{matrix}

8.7.6Conversion d’un quaternion en angles d’Euler

Pour extraire les angles d’Euler d’un quaternion, nous pourrions résoudre les angles d’Euler à partir de l’Équation (8.33) directement. Cependant, voyons si nous pouvons tirer parti de notre travail dans les sections précédentes et obtenir la réponse sans autant d’efforts. Nous avons déjà développé une technique pour extraire les angles d’Euler d’une matrice à la Section 8.7.2. Et nous avons montré comment convertir un quaternion en matrice. Donc prenons simplement notre technique de conversion d’une matrice en angles d’Euler et substituons nos résultats de l’Équation (8.20).

Notre méthode de la Section 8.7.2 pour extraire les angles d’Euler d’une matrice objet-vers-droit est résumée ci-dessous.

p=arcsin(m32)h={atan2(m31,m33)atan2(m13,m11)si cosp0,sinon.b={atan2(m12,m22)0si cosp0,sinon.\begin{matrix} p & {= \arcsin( - m_{32})} & & & & \\ h & {= \left\{ \begin{matrix} {{atan2}(m_{31},m_{33})} \\ {{atan2}( - m_{13},m_{11})} \\ \end{matrix} \right.} & & \begin{matrix} {\text{si~}\cos p \neq 0,} \\ {\text{sinon.}} \\ \end{matrix} & & \\ b & {= \left\{ \begin{matrix} {{atan2}(m_{12},m_{22})} \\ 0 \\ \end{matrix} \right.} & & \begin{matrix} {\text{si~}\cos p \neq 0,} \\ {\text{sinon.}} \\ \end{matrix} & & \\ \end{matrix}

Pour votre commodité, nous répétons les éléments matriciels nécessaires de l’Équation (8.20) :

m11=12y22z2,m12=2xy+2wz,m13=2xz2wy,m22=12x22z2,m31=2xz+2wy,m32=2yz2wx,m33=12x22y2.\begin{matrix} m_{11} & {= 1 - 2y^{2} - 2z^{2},} & m_{12} & {= 2xy + 2wz,} & m_{13} & {= 2xz - 2wy,} \\ & & m_{22} & {= 1 - 2x^{2} - 2z^{2},} & & \\ m_{31} & {= 2xz + 2wy,} & m_{32} & {= 2yz - 2wx,} & m_{33} & {= 1 - 2x^{2} - 2y^{2}.} \\ \end{matrix}

En substituant les Équations (8.37)(8.39) dans les Équations (8.34)(8.36) et en simplifiant, nous obtenons

p=arcsin(m32)=arcsin(2(yzwx))h={atan2(m31,m33)=atan2(2xz+2wy,12x22y2)si cosp0,=atan2(xz+wy,1/2x2y2)atan2(m13,m11)=atan2(2xz+2wy,12y22z2)sinon.=atan2(xz+wy,1/2y2z2)b={atan2(m12,m22)=atan2(2xy+2wz,12x22z2)si cosp0,=atan2(xy+wz,1/2x2z2)0sinon.\begin{matrix} p & {= \arcsin( - m_{32})} \\ & {= \arcsin\left( - 2(yz - wx) \right)} \\ h & {= \left\{ \begin{matrix} {{atan2}(m_{31},m_{33})} & \\ {\ = {atan2}(2xz + 2wy,1 - 2x^{2} - 2y^{2})} & {\text{si~}\cos p \neq 0,} \\ {\ = {atan2}(xz + wy,1/2 - x^{2} - y^{2})} & \\ {\mspace{6mu}\quad} & \\ {{atan2}( - m_{13},m_{11})} & \\ {\ = {atan2}( - 2xz + 2wy,1 - 2y^{2} - 2z^{2})} & {\text{sinon.}} \\ {\ = {atan2}( - xz + wy,1/2 - y^{2} - z^{2})} & \\ \end{matrix} \right.} \\ b & {= \left\{ \begin{matrix} {{atan2}(m_{12},m_{22})} & \\ {\ = {atan2}(2xy + 2wz,1 - 2x^{2} - 2z^{2})} & {\text{si~}\cos p \neq 0,} \\ {\ = {atan2}(xy + wz,1/2 - x^{2} - z^{2})} & \\ {\mspace{6mu}\quad} & \\ 0 & {\text{sinon.}} \\ \end{matrix} \right.} \\ \end{matrix}

Nous pouvons traduire cela directement en code, comme le montre le Listing 8.6, qui convertit un quaternion objet-vers-droit en angles d’Euler.

// Quaternion d'entrée
float w,x,y,z;

// Angles d'Euler de sortie (radians)
float h,p,b;

// Extraire sin(tangage)
float sp = -2.0f * (y*z - w*x);

// Vérifier le blocage de Cardan, avec une légère tolérance
// pour l'imprécision numérique
if (fabs(sp) > 0.9999f) {

    // Regarder directement vers le haut ou vers le bas
    p = 1.570796f * sp; // pi/2

    // Calculer le cap, forcer le roulis à zéro
    h = atan2(-x*z + w*y, 0.5f - y*y - z*z);
    b = 0.0f;

} else {

    // Calculer les angles
    p = asin(sp);
    h = atan2(x*z + w*y, 0.5f - x*x - y*y);
    b = atan2(x*y + w*z, 0.5f - x*x - z*z);
}

Pour convertir un quaternion droit-vers-objet en format angle d’Euler, nous utilisons un code presque identique, mais avec les valeurs xx , yy et zz negées, car nous supposons que le quaternion droit-vers-objet est le conjugué du quaternion objet-vers-droit.

// Extraire sin(tangage)
float sp = -2.0f * (y*z + w*x);

// Vérifier le blocage de Cardan, avec une légère tolérance
// pour l'imprécision numérique
if (fabs(sp) > 0.9999f) {

    // Regarder directement vers le haut ou vers le bas
    p = 1.570796f * sp; // pi/2

    // Calculer le cap, forcer le roulis à zéro
    h = atan2(-x*z - w*y, 0.5f - y*y - z*z);
    b = 0.0f;

} else {

    // Calculer les angles
    p = asin(sp);
    h = atan2(x*z - w*y, 0.5f - x*x - y*y);
    b = atan2(x*y - w*z, 0.5f - x*x - z*z);
}

Exercices

image

Figure 8.13 Exemples d’orientations pour les exercices 1, 2, 4 et 5.

  1. Associez chacune des matrices de rotation ci-dessous avec l’orientation correspondante de la Figure 8.13. Ces matrices transforment les vecteurs-ligne à gauche de l’espace objet vers l’espace droit.

    1. (a) [0.7070.0000.7070.7070.0000.7070.0001.0000.000]\begin{bmatrix} 0.707 & 0.000 & 0.707 \\ 0.707 & 0.000 & {- 0.707} \\ 0.000 & 1.000 & 0.000 \\ \end{bmatrix}

    2. (b) [1.0000.0000.0000.0000.7070.7070.0000.7070.707]\begin{bmatrix} 1.000 & 0.000 & 0.000 \\ 0.000 & {- 0.707} & 0.707 \\ 0.000 & {- 0.707} & {- 0.707} \\ \end{bmatrix}

    3. (c) [0.0610.8140.5780.9000.2960.3220.4330.5000.750]\begin{bmatrix} 0.061 & 0.814 & 0.578 \\ {- 0.900} & 0.296 & {- 0.322} \\ {- 0.433} & {- 0.500} & 0.750 \\ \end{bmatrix}

    4. (d) [0.7130.4500.5380.0910.7020.7060.6960.5520.460]\begin{bmatrix} {- 0.713} & {- 0.450} & {- 0.538} \\ 0.091 & 0.702 & {- 0.706} \\ 0.696 & {- 0.552} & {- 0.460} \\ \end{bmatrix}

    5. (e) [1.0000.0000.0000.0001.0000.0000.0000.0001.000]\begin{bmatrix} 1.000 & 0.000 & 0.000 \\ 0.000 & 1.000 & 0.000 \\ 0.000 & 0.000 & 1.000 \\ \end{bmatrix}

    6. (f) [0.7070.0000.7070.5000.7070.5000.5000.7070.500]\begin{bmatrix} {- 0.707} & 0.000 & 0.707 \\ 0.500 & 0.707 & 0.500 \\ {- 0.500} & 0.707 & {- 0.500} \\ \end{bmatrix}

  2. Associez chacun des triplets d’angles d’Euler suivants avec l’orientation correspondante de la Figure 8.13, et déterminez si l’orientation est dans l’ensemble canonique des angles d’Euler. Sinon, expliquez pourquoi.

    1. (a)h = 180o180^{o} , p=45op = 45^{o} , b=180ob = 180^{o}

    2. (b)h = 135o- 135^{o} , p=45op = - 45^{o} , b=0ob = 0^{o}

    3. (c)h = 0o0^{o} , p=90op = - 90^{o} , b=45ob = - 45^{o}

    4. (d)h = 123o123^{o} , p=33.5op = 33.5^{o} , b=32.7ob = - 32.7^{o}

    5. (e)h = 0o0^{o} , p=0op = 0^{o} , b=0ob = 0^{o}

    6. (f)h = 0o0^{o} , p=135op = 135^{o} , b=0ob = 0^{o}

    7. (g)h = 45o- 45^{o} , p=90op = - 90^{o} , b=0ob = 0^{o}

    8. (h)h = 180o180^{o} , p=180op = - 180^{o} , b=180ob = 180^{o}

    9. (i)h = 30o- 30^{o} , p=30op = 30^{o} , b=70ob = 70^{o}

    1. Construire un quaternion pour effectuer une rotation de 30° autour de l’axe xx .

    2. Quelle est la magnitude de ce quaternion ?

    3. Quel est son conjugué ?

    4. Supposer que le quaternion est utilisé pour effectuer la rotation des points de l’espace objet vers l’espace droit d’un certain objet. Quelle est l’orientation, en angles d’Euler, de cet objet ?

  3. Associez chacun des quaternions suivants avec l’orientation correspondante de la Figure 8.13. Ces quaternions transforment les vecteurs de l’espace objet vers l’espace droit. (Nous vous avions dit que les quaternions sont plus difficiles à utiliser pour les humains ! Essayez de les convertir en forme matricielle ou en angles d’Euler et tirez parti de votre travail précédent.)

    1. (a) [1.000(0.0000.0000.000)]\begin{bmatrix} {- 1.000} & \begin{pmatrix} 0.000 & 0.000 & 0.000 \\ \end{pmatrix} \\ \end{bmatrix}

    2. (b) [0.653(0.6530.2710.271)]\begin{bmatrix} 0.653 & \begin{pmatrix} {- 0.653} & {- 0.271} & {- 0.271} \\ \end{pmatrix} \\ \end{bmatrix}

    3. (c) [0.364(0.1060.8480.372)]\begin{bmatrix} 0.364 & \begin{pmatrix} {- 0.106} & 0.848 & {- 0.372} \\ \end{pmatrix} \\ \end{bmatrix}

    4. (d) [0.383(0.9240.0000.000)]\begin{bmatrix} 0.383 & \begin{pmatrix} 0.924 & 0.000 & 0.000 \\ \end{pmatrix} \\ \end{bmatrix}

    5. (e) [1.000(0.0000.0000.000)]\begin{bmatrix} 1.000 & \begin{pmatrix} 0.000 & 0.000 & 0.000 \\ \end{pmatrix} \\ \end{bmatrix}

    6. (f) [0.364(0.1060.8480.372)]\begin{bmatrix} {- 0.364} & \begin{pmatrix} 0.106 & {- 0.848} & 0.372 \\ \end{pmatrix} \\ \end{bmatrix}

    7. (g) [0.354(0.1460.8530.354)]\begin{bmatrix} 0.354 & \begin{pmatrix} {- 0.146} & {- 0.853} & {- 0.354} \\ \end{pmatrix} \\ \end{bmatrix}

    8. (h) [0.726(0.0610.3480.590)]\begin{bmatrix} 0.726 & \begin{pmatrix} 0.061 & {- 0.348} & 0.590 \\ \end{pmatrix} \\ \end{bmatrix}

    9. (i) [0.383(0.9240.0000.000)]\begin{bmatrix} {- 0.383} & \begin{pmatrix} {- 0.924} & 0.000 & 0.000 \\ \end{pmatrix} \\ \end{bmatrix}

  4. Associez chacune des orientations axe-angle suivantes avec l’orientation correspondante de la Figure 8.13. (Indice : cela peut être assez difficile à visualiser. Essayez de convertir l’axe et l’angle en quaternion et utilisez ensuite les résultats de vos calculs précédents. Voyez ensuite si vous pouvez le visualiser.)

    1. (a) 98.4o,[0.863,0.357,0.357]98.4^{o},\lbrack - 0.863, - 0.357, - 0.357\rbrack

    2. (b) 0o,[0.707,0.707,0.000]0^{o},\lbrack 0.707, - 0.707,0.000\rbrack

    3. (c) 87.0o,[0.089,0.506,0.857]87.0^{o},\lbrack 0.089, - 0.506,0.857\rbrack

    4. (d) 137o,[0.114,0.910,0.399]137^{o},\lbrack - 0.114,0.910,0.399\rbrack

    5. (e) 135o,[1.000,0.000,0.000]135^{o},\lbrack 1.000,0.000,0.000\rbrack

    6. (f) 261.6o,[0.863,0.357,0.357]261.6^{o},\lbrack 0.863,0.357,0.357\rbrack

    7. (g) 139o,[0.156,0.912,0.378]139^{o},\lbrack - 0.156, - 0.912, - 0.378\rbrack

    8. (h) 7200o,[0.000,1.000,0.000]7200^{o},\lbrack 0.000, - 1.000,0.000\rbrack

    9. (i) 135o,[1.000,0.000,0.000]- 135^{o},\lbrack - 1.000,0.000,0.000\rbrack

  5. Dériver la formule de multiplication des quaternions, en interprétant les quaternions comme des nombres complexes 4D et en appliquant les règles de l’Équation (8.10).

  6. Calculer un quaternion qui effectue deux fois la rotation du quaternion [0.965(0.1490.1490.149)]\begin{bmatrix} 0.965 & \begin{pmatrix} 0.149 & {- 0.149} & 0.149 \\ \end{pmatrix} \\ \end{bmatrix} .

  7. Considérer les quaternions :

    𝐚=[0.233(0.0600.2570.935)]𝐛=[0.752(0.2860.3740.459)]\begin{matrix} \mathbf{a} & {=} & \begin{bmatrix} 0.233 & \begin{pmatrix} 0.060 & {- 0.257} & {- 0.935} \\ \end{pmatrix} \\ \end{bmatrix} \\ \mathbf{b} & {=} & \begin{bmatrix} {- 0.752} & \begin{pmatrix} 0.286 & 0.374 & 0.459 \\ \end{pmatrix} \\ \end{bmatrix} \\ \end{matrix}

    1. (a)Calculer le produit scalaire 𝐚𝐛\mathbf{a} \cdot \mathbf{b} .

    2. (b)Calculer le produit quaternionique 𝐚𝐛\mathbf{a}\mathbf{b} .

    3. (c)Calculer la différence de 𝐚\mathbf{a} à 𝐛\mathbf{b} .

  8. Prouver l’affirmation faite à la Section 8.5.7 : la magnitude du produit de deux quaternions est le produit des magnitudes.

  9. Développer la multiplication 𝐪𝐯𝐪1\mathbf{q}\mathbf{v}\mathbf{q}^{- 1} , et vérifier que la matrice de l’Équation (8.20) est correcte.

  10. Faire une étude de quelques moteurs de jeu et de code open source et déterminer les conventions concernant les vecteurs-ligne/colonne, les matrices de rotation et les angles d’Euler.

Je porte un collier, parce que je veux savoir quand je suis à l’envers.

— Mitch Hedberg (1968–2005)

Références

[1] G. H. Bryan.   Stability In Aviation: An Introduction to Dynamical Stability as Applied to the Motions of Aeroplanes.   London: Macmillan and Co., 1911.

[2] Erik B. Dam, Martin Koch, and Martin Lillholm.   “Quaternions, Interpolation and Animation.”   Technical Report DIKU-TR-98/5, Department of Computer Science, University of Copenhagen, 1998.   http://www.diku.dk/students/myth/quat.html.

[3] James Diebel.   “Representing Attitude: Euler Angles, Unit Quaternions, and Rotation Vectors.”   http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.110.5134, 2006.

[4] Fletcher Dunn and Ian Parberry.   3D Math Primer for Graphics and Game Development, First edition.   Plano, TX: Wordware Publishing, 2002.

[5] F. Sebastin Grassia.   “Practical Parameterization of Rotations Using the Exponential Map.”   J. Graph. Tools 3 (1998), 29–48.   http://jgt.akpeters.com/papers/Grassia98/.

[6] Andrew J. Hanson.   Visualizing Quaternions (The Morgan Kaufmann Series in Interactive 3D Technology).   San Francisco: Morgan Kaufmann, 2006.

[7] John C. Hart, George K. Francis, and Louis H. Kauffman.   “Visualizing Quaternion Rotation.”   ACM Trans. Graph. 13:3 (1994), 256–276.

[8] Jack B. Kuipers.   Quaternions and Rotation Sequences: A Primer with Applications to Orbits, Aerospace, and Virtual Reality.   Princeton, NJ: Princeton University Press, 1999.

[9] John McDonald.   “Teaching Quaternions Is Not Complex.”   Computer Graphics Forum 29:8 (2010), 2447–2455.

[10] Oliver M. O’Reilly.   Intermediate Dynamics for Engineers: A Unified Treatment of Newton–Euler and Lagrangian Mechanics.   Cambridge, UK: Cambridge University Press, 2008.

[11] Ken Shoemake.   “Quaternions and 4×44 \times 4 Matrices.”   In Graphics Gems II, edited by James Arvo. San Diego: Academic Press Professional, 1991.

[12] Ken Shoemake.   “Euler Angle Conversion.”   In Graphics Gems IV, edited by Paul S. Heckbert. San Diego: Academic Press Professional, 1994.

  1. En réalité, nous pouvons aussi mettre les vecteurs dans les colonnes d’une matrice. Cela est certainement vrai si nous utilisons des vecteurs-colonne — mais il s’avère que cela fonctionne même si nous préférons utiliser des vecteurs-ligne. C’est parce que les matrices de rotation sont orthonormales, ce qui signifie que nous pouvons les inverser en prenant leur transposée. Nous en discutons à la Section 8.2.1.

  2. Nous mesurons la fréquence d’utilisation en fonction du nombre de fois que l’opération est codée, et non de la fréquence à laquelle elle est exécutée à l’exécution. Par exemple, la transformation des sommets à travers le pipeline graphique est certainement une opération matricielle extrêmement couramment utilisée, mais il y a relativement peu de lignes de code qui effectuent cette opération. Cela s’est avéré vrai dans une grande variété de genres de jeux, tels que les courses, les combats, les jeux de société 3D et les jeux de tir, bien que, bien sûr, nous ne puissions pas parler pour l’environnement de travail de chacun.

  3. En réalité, probablement la multiplication par la transposée, puisque les matrices de rotation sont orthogonales — mais ce n’est pas le point ici.

  4. C’est un avantage souvent mis en avant des quaternions qu’ils peuvent être utilisés pour effectuer des rotations par multiplication de quaternions (voir Section 8.5.7). Cependant, si nous examinons les mathématiques, nous voyons que ce « raccourci » équivaut à une multiplication par la matrice de rotation correspondante.

  5. C’est probablement un peu présomptueux de notre part de qualifier lacap-tangage-roulis de variation. Après tout, il existe un article Wikipedia sur le lacet-tangage-roulis, mais aucun sur le cap-tangage-roulis, alors qui peut dire que notre préférence n’est pas la variation ? Nous admettons cette présomption et sommes prêts à défendre notre préférence sous peu.

  6. Le mot « aéronautique » en est un exemple.

  7. Il y a aussi beaucoup de personnes peu avisées qui ne ont pas de bonnes raisons pour les choix qu’elles font — mais au final, le résultat est le même.

  8. La raison en est que cela provient de la branche des mathématiques tout aussi intimidante et obscure connue sous le nom d’algèbre de Lie. (Lie se prononce « li », car c’est le nom d’une personne.) La carte exponentielle a une définition plus large dans ce contexte, et l’espace des rotations 3D (parfois noté SO(3)SO(3)) est juste un type de groupe de Lie. D’autres commentaires regrettables sur la terminologie à venir.

  9. Dans ce cas, le mot « avancé » signifie « en dehors de l’expertise des auteurs. »

  10. C’est-à-dire, si vos bibliothèques de classes sont bien conçues.

  11. Avec nos excuses auprès de nos lecteurs en Inde, nous préférons la gauche.

  12. En fait, vous avez une certaine flexibilité si vous êtes prêt à aller à contre-courant. Certains auteurs audacieux \cite_need_fixup{first-edition} sont allés jusqu’à fournir une définition alternative du produit quaternionique avec les opérandes inversés. Cela peut mener à un code plus facile à comprendre, et cette option pourrait valoir la peine d’être considérée dans votre propre code. Cependant, nous nous en tiendrons au standard dans ce livre.

  13. C’est la lettre grecque oméga, prononcée « oh-MAY-gah. »

  14. Notre convention habituelle est d’utiliser des vecteurs-ligne, mais nous allons utiliser des vecteurs-colonne ici car l’ordre de droite à gauche des rotations correspond plus étroitement aux quaternions.

  15. La question de savoir si la rotation est dans le sens des aiguilles d’une montre ou dans le sens contraire est une question de convention et n’est pas inhérente aux nombres complexes. En fait, vous avez probablement déjà remarqué que nous aurions pu nier l’autre bb dans la matrice de l’Équation (8.9) et avoir encore un moyen valide d’associer l’ensemble des nombres complexes aux matrices 2×22 \times 2 . Notre choix arbitraire deviendra utile dans un instant.

  16. Probablement ceux qui connaissent déjà tout cela. Hé, que faites-vous dans la pataugeoire — n’avez-vous pas des sauts arrière depuis le plongeoir à faire en ce moment ?

  17. Y compris la première édition de ce livre \cite_need_fixup{first-edition}.

<< Systèmes de coordonnées polaires

Retour en haut

Primitives géométriques >>