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′=(p′x,p′y,p′z)
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,−u⋅v)(−u,s)=((−u⋅v)(−u)+s(sv+u× v)+(sv+u×v)×(−u),…)=((u⋅v)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′=(u⋅v)u+s2v+s(u×v)+s(u×v)+u×(u×v)=(u⋅v)u+s2v+2s(u×v)+(u⋅v)u−(u⋅u)v=2(u⋅v)u+(s2−u⋅u)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);
}
vprime = v + ((cross(u, v) * s) + cross(u, cross(u, v)) * 2.0f
Est-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 leoperator*
qui prend un quaternion et un vecteur (vec<3, T, Q> operator*(qua<T, Q> const& q, vec<3, T, Q> const& v)
)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.)
la source
Première observation: l'inverse de
q
n'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 estnorm(q)^2=q*conjugate(q)=1
et 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é estconjugate(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.où
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!
la source
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
la source
J'ai essayé de résoudre ce problème à la main et j'ai trouvé l'équation / méthode suivante:
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.
la source