Vecteur tournant3 par un quaternion

25

J'essaie de faire pivoter un vecteur3 d'un quaternion donné.

Je sais que c'est vrai

v=qvq1

Je sais que q1 est l'inverse qui vient qmagnitude(q) , mais comment mapper la multiplication du vecteur au quaternion pour récupérer un vecteur?

J'ai trouvé que vous pouvez traiter v comme une matrice, et convertir q et q en matrices, puis convertir v d'une matrice en vecteur, mais cela semble un peu exagéré juste pour obtenir un vecteur. Existe-t-il une mise en œuvre plus propre que je pourrais utiliser?

gardian06
la source

Réponses:

36

Comme Nathan Reed et teodron l'ont exposé, la recette pour faire tourner un vecteur v par un quaternion q de longueur unitaire est:

1) Créez un quaternion pur p à partir de v . Cela signifie simplement ajouter une quatrième coordonnée de 0:

p=(vx,vy,vz,0)p=(v,0)

2) Pré-multipliez-le avec q et post-multipliez-le avec le conjugué q * :

p=q×p×q

3) Cela se traduira par un autre quaternion pur qui peut être transformé en vecteur:

v=(px,py,pz)

Ce vecteur v est v tourné de q .


Cela fonctionne mais loin d'être optimal . Les multiplications du quaternion signifient des tonnes et des tonnes d'opérations. J'étais curieux de connaître diverses implémentations comme celle-ci et j'ai décidé de trouver d'où elles venaient. Voici mes découvertes.

On peut aussi décrire q comme la combinaison d'un vecteur tridimensionnel u et d'un scalaire s :

q=(ux,uy,uz,s)q=(u,s)

Selon les règles de la multiplication du quaternion , et comme le conjugué d'un quaternion de longueur unitaire est simplement son inverse, nous obtenons:

p=qpq=(u,s)(v,0)(u,s)=(sv+u×v,uv)(u,s)=((uv)(u)+s(sv+u× v)+(sv+u×v)×(u),)=((uv)u+s2v+s(u×v)+sv×(u)+(u×v)×(u),)

La partie scalaire (ellipses) donne zéro, comme détaillé ici . Ce qui est intéressant, c'est la partie vectorielle, AKA notre vecteur pivoté v ' . Il peut être simplifié à l'aide de quelques identités vectorielles de base :

v=(uv)u+s2v+s(u×v)+s(u×v)+u×(u×v)=(uv)u+s2v+2s(u×v)+(uv)u(uu)v=2(uv)u+(s2uu)v+2s(u×v)

C'est maintenant beaucoup plus optimal ; deux produits scalaires, un produit croisé et quelques extras: environ la moitié des opérations. Ce qui donnerait quelque chose comme ça dans le code source (en supposant une bibliothèque mathématique vectorielle générique):

void rotate_vector_by_quaternion(const Vector3& v, const Quaternion& q, Vector3& vprime)
{
    // Extract the vector part of the quaternion
    Vector3 u(q.x, q.y, q.z);

    // Extract the scalar part of the quaternion
    float s = q.w;

    // Do the math
    vprime = 2.0f * dot(u, v) * u
          + (s*s - dot(u, u)) * v
          + 2.0f * s * cross(u, v);
}
Laurent Couvidou
la source
Chapeau à une meilleure réponse écrite. Et étant donné que la plupart des monstres de performances ont tendance à utiliser des intrinsèques pour effectuer des opérations vectorielles, vous obtenez une accélération assez importante (même pour la multiplication simple du quaternion, en particulier sur les architectures Intel).
teodron
Le résultat final ressemble à la formule de rotation de Rodrigues - il a de toute façon les mêmes vecteurs de base; Je devrais creuser dans certaines identités trigonométriques pour voir si les coefficients correspondent.
Nathan Reed
@NathanReed Cela semble être une autre façon d'arriver au même résultat. J'aimerais aussi savoir si cela correspond. Merci d'avoir fait remarquer cela!
Laurent Couvidou
1
Je vérifiais l'implémentation de GLM de cela et cela semble être implémenté un peu différemment, à savoir comme suit: vprime = v + ((cross(u, v) * s) + cross(u, cross(u, v)) * 2.0fEst-ce une optimisation similaire? Il semble quelque peu similaire, mais n'est pas le même - il utilise uniquement des produits croisés, pas de produits scalaires. Le code source d' origine se trouve dans le fichier de type_quat.inl de dépôt officiel GLM dans le operator*qui prend un quaternion et un vecteur ( vec<3, T, Q> operator*(qua<T, Q> const& q, vec<3, T, Q> const& v))
j00hi
7

Tout d'abord, q ^ (- 1) n'est pas -q / magnitude (q); c'est q * / (magnitude (q)) ^ 2 (q * est le conjugué; qui annule toutes les composantes sauf la vraie). Bien sûr, vous pouvez laisser la division en ordre de grandeur si tous vos quaternions sont déjà normalisés, ce qui serait généralement dans un système de rotation.

Quant à la multiplication avec un vecteur, vous étendez simplement le vecteur à un quaternion en définissant la composante réelle d'un quat à zéro et ses composants ijk au xyz du vecteur. Ensuite, vous faites les multiplications du quaternion pour obtenir v ', puis vous extrayez à nouveau les composants ijk. (La partie réelle de v 'devrait toujours sortir nulle, plus ou moins une erreur en virgule flottante.)

Nathan Reed
la source
5

Première observation: l'inverse de qn'est pas -q/magnitude(q), c'est complètement faux. Les rotations avec des quaternions impliquent que ces équivalents de nombres complexes 4D ont une norme unitaire, se trouvent donc sur la sphère unitaire S3 dans cet espace 4D. Le fait qu'un quat est unitaire signifie que sa norme est norm(q)^2=q*conjugate(q)=1et cela signifie que l'inverse du quat est son conjugué.

Si un quaternion unitaire s'écrit q=(w,x,y,z)= (cos (t), sin (t) v ), alors son conjugué est conjugate(q)=(w,-x,-y,-z)= (cos (t), - sin (t) v ), où t est la moitié de l'angle de rotation et v est l'axe de rotation (en tant que vecteur unitaire, bien sûr).

Lorsque ce mec de Hamilton a décidé de jouer avec des équivalents de nombres complexes dans des dimensions plus élevées, il est également tombé sur de belles propriétés. Par exemple, si vous utilisez un quaternion complètement pur q=(0,x,y,z)(pas de partie scalaire w !), Vous pouvez considérer cette merde comme un vecteur (c'est en fait un quat sur ce que les gens pourraient appeler l'équateur de la sphère S3, qui est une sphère S2! ! - Des trucs hallucinants si nous considérons à quel point les personnes techniquement handicapées du 19ème siècle nous semblent aujourd'hui des cowboys eyePhone). Hamilton a donc pris ce vecteur sous sa forme quat: v=(0,x,y,z)et a fait une série d'expériences en considérant les propriétés géométriques des quats.

INPUT: _v=(x,y,z)_ a random 3D vector to rotate about an __u__ unit axis by an angle of _theta_

OUTPUT: q*(0,_v_)*conjugate(q)

 q = (cos(theta/2), sin(theta/2)*u)
 conjugate(q) = inverse(q) = (cos(theta/2), -sin(theta/2)*u)
 norm(q)=magnitude(q)=|q|=1

Observation: le q * (0, v) * conj (q) doit être un autre quat de la forme (0, v '). Je ne passerai pas en revue toute cette explication apparemment compliquée de la raison pour laquelle cela se produit, mais si vous faites pivoter un quaternion imaginaire pur (ou un vecteur dans notre cas!) Grâce à cette méthode, vous devez obtenir un type d'objet similaire: quat imaginaire pur. et vous prenez pour résultat sa part imaginaire. Voilà, le monde merveilleux des rotations avec des quaternions dans une coquille de noix.

NOTE : à quiconque se jette avec cette phrase galvaudée: les quats sont bons parce qu'ils évitent les verrous de cardan .. devraient d'abord libérer leur imagination !! Les quats sont un simple appareil mathématique "élégant" et peuvent être évités en utilisant d'autres approches, celle que je trouve complètement équivalente géométriquement étant l'approche de l'angle d'axe.

CODE : la bibliothèque C ++ que je préfère est plutôt simpliste, mais possède toutes les opérations matricielles, vectorielles et quaternaires dont un expérimentateur graphique 3D devrait avoir besoin sans avoir à perdre plus de 15 minutes pour l'apprendre. Vous pouvez tester les choses que j'ai écrites ici en utilisant cela en 15 minutes si vous n'êtes pas novice en C ++. Bonne chance!

teodron
la source
+1 pour votre note. Je parie que la plupart des gens ne pourraient pas obtenir un véritable verrouillage du cardan s'ils essayaient.C'est devenu une phrase fourre-tout pour tout comportement inattendu lors des rotations.
Steve H
La plupart des gens ne peuvent pas construire un mécanisme de cardan approprié et pensent que s'ils enchaînent 3 matrices de rotation, ils se retrouvent automatiquement avec la représentation des "angles d'Euler". Le truc de cardan n'est que l'un des types de rotation de bras de robot les plus simples. les articulations qui peuvent subir une redondance lorsque vous essayez d'effectuer une cinématique inverse (elle a plus de degrés de liberté qu'il n'en a réellement besoin pour produire l'orientation souhaitée). Eh bien, c'est un autre sujet, mais j'ai pensé qu'il était agréable de rester à l'écart du battage médiatique que ce problème "légendaire" a généré parmi les programmeurs CG.
teodron
Nitpickery: alors que l'axe-angle est équivalent en ce que les deux représentations peuvent représenter toutes les rotations dans SO (3) de manière unique (d'accord, modulo la double couverture habituelle) et bien sûr il y a une transformation presque triviale entre eux, les quaternions ont l'avantage d'être beaucoup plus facile à composer que toutes les autres représentations non matricielles.
Steven Stadnicki
Ils ont l'avantage d'être plus faciles à composer en raison de leur comportement agréable dans n'importe quel langage de programmation orienté objet, en particulier lors de l'utilisation d'une surcharge d'opérateur. Je ne suis pas sûr, mais peut-être même que leurs propriétés d'interpolation sphérique se conservent pour l'axe-angle (sauf pour SQUAD peut-être?!).
teodron
2

Voici une manière alternative de transformer un vecteur par un quaternion. C'est la façon dont MS le fait dans le cadre xna. http://pastebin.com/fAFp6NnN

Steve H
la source
-1

J'ai essayé de résoudre ce problème à la main et j'ai trouvé l'équation / méthode suivante:

// inside quaterion class
// quaternion defined as (r, i, j, k)
Vector3 rotateVector(const Vector3 & _V)const{
    Vector3 vec();   // any constructor will do
    vec.x = 2*(r*_V.z*j + i*_V.z*k - r*_V.y*k + i*_V.y*j) + _V.x*(r*r + i*i - j*j - k*k);
    vec.y = 2*(r*_V.x*k + i*_V.x*j - r*_V.z*i + j*_V.z*k) + _V.y*(r*r - i*i + j*j - k*k);
    vec.z = 2*(r*_V.y*i - r*_V.x*j + i*_V.x*k + j*_V.y*k) + _V.z*(r*r - i*i - j*j + k*k);
    return vec;
}

J'apprécierais que quelqu'un examine la dérivation mt que j'ai utilisée http://pastebin.com/8QHQqGbv Je suggère de copier dans un éditeur de texte qui prend en charge le défilement latéral

dans ma notation, j'ai utilisé q ^ (- 1) pour signifier conjugué, et non inverse, et différents identifiants, mais j'espère que c'est suivable. Je pense que la majorité a raison, surtout là où, en prouvant, la partie réelle du vecteur disparaîtrait.

gardian06
la source