J'ai deux vecteurs u et v. Existe-t-il un moyen de trouver un quaternion représentant la rotation de u vers v?
math
vector
quaternions
sdfqwerqaz1
la source
la source
crossproduct
ne sera pas valide dans ces cas, vous devez donc d'abord vérifierdot(v1, v2) > 0.999999
etdot(v1, v2) < -0.999999
, respectivement, et soit renvoyer une identité quat pour les vecteurs parallèles, soit renvoyer une rotation de 180 degrés (autour de n'importe quel axe) pour les vecteurs opposés.sqrt((v1.Length ^ 2) * (v2.Length ^ 2))
simplifie àv1.Length * v2.Length
. Je ne pouvais obtenir aucune variation de ceci pour produire des résultats raisonnables.Solution de vecteur à demi-chemin
J'ai trouvé la solution que je crois qu'Imbrondir essayait de présenter (bien qu'avec une petite erreur, ce qui explique probablement pourquoi sinisterchipmunk avait du mal à la vérifier).
Étant donné que nous pouvons construire un quaternion représentant une rotation autour d'un axe comme ceci:
Et que le point et le produit croisé de deux vecteurs normalisés sont:
Étant donné qu'une rotation de u vers v peut être obtenue en tournant par thêta (l'angle entre les vecteurs) autour du vecteur perpendiculaire, il semble que nous puissions construire directement un quaternion représentant une telle rotation à partir des résultats du point et des produits croisés ; cependant, tel quel, thêta = angle / 2 , ce qui signifie que cela entraînerait le double de la rotation souhaitée.
Une solution consiste à calculer un vecteur à mi-chemin entre u et v , et à utiliser le point et le produit croisé de u et le vecteur à mi-chemin pour construire un quaternion représentant une rotation de deux fois l'angle entre u et le vecteur à mi-chemin , ce qui nous amène à v !
Il existe un cas particulier, où u == -v et un vecteur unique à mi-chemin devient impossible à calculer. Ceci est attendu, étant donné les rotations infiniment nombreuses de "l'arc le plus court" qui peuvent nous faire passer de u à v , et nous devons simplement tourner de 180 degrés autour de tout vecteur orthogonal à u (ou v ) comme solution de cas particulier. Ceci est fait en prenant le produit croisé normalisé de u avec tout autre vecteur non parallèle à u .
Le pseudo-code suit (évidemment, en réalité, le cas particulier devrait tenir compte des inexactitudes en virgule flottante - probablement en comparant les produits scalaires à un certain seuil plutôt qu'à une valeur absolue).
Notez également qu'il n'y a pas de cas particulier où u == v (le quaternion d'identité est produit - vérifiez et voyez par vous-même).
La
orthogonal
fonction renvoie tout vecteur orthogonal au vecteur donné. Cette implémentation utilise le produit croisé avec le vecteur de base le plus orthogonal.Solution Quaternion à mi-chemin
C'est en fait la solution présentée dans la réponse acceptée, et elle semble être légèrement plus rapide que la solution vectorielle à mi-chemin (~ 20% plus rapide par mes mesures, mais ne me croyez pas sur parole). Je l'ajoute ici au cas où d'autres comme moi seraient intéressés par une explication.
Essentiellement, au lieu de calculer un quaternion à l'aide d'un vecteur à mi-chemin, vous pouvez calculer le quaternion qui entraîne deux fois la rotation requise (comme détaillé dans l'autre solution), et trouver le quaternion à mi-chemin entre cela et zéro degré.
Comme je l'ai expliqué précédemment, le quaternion pour le double de la rotation requise est:
Et le quaternion pour une rotation nulle est:
Le calcul du quaternion à mi-chemin est simplement une question de sommation des quaternions et de normalisation du résultat, tout comme avec les vecteurs. Cependant, comme c'est aussi le cas avec les vecteurs, les quaternions doivent avoir la même grandeur, sinon le résultat sera biaisé vers le quaternion avec la plus grande grandeur.
Un quaternion construit à partir du point et produit croisé de deux vecteurs aura le même ordre de grandeur que ces produits:
length(u) * length(v)
. Plutôt que de diviser les quatre composants par ce facteur, nous pouvons à la place augmenter le quaternion d'identité. Et si vous vous demandez pourquoi la réponse acceptée complique apparemment les choses en utilisantsqrt(length(u) ^ 2 * length(v) ^ 2)
, c'est parce que la longueur au carré d'un vecteur est plus rapide à calculer que la longueur, nous pouvons donc enregistrer unsqrt
calcul. Le résultat est:Et puis normalisez le résultat. Le pseudo code suit:
la source
Le problème tel qu'énoncé n'est pas bien défini: il n'y a pas de rotation unique pour une paire de vecteurs donnée. Prenons le cas, par exemple, où u = <1, 0, 0> et v = <0, 1, 0> . Une rotation de u à v serait une rotation pi / 2 autour de l'axe z. Une autre rotation de u vers v serait une rotation pi autour du vecteur <1, 1, 0> .
la source
Pourquoi ne pas représenter le vecteur à l'aide de quaternions purs? C'est mieux si vous les normalisez d'abord peut-être.
q 1 = (0 u x u y u z ) '
q 2 = (0 v x v y v z )'
q 1 q rot = q 2
Pré-multipliez avec q 1 -1
q rot = q 1 -1 q 2
où q 1 -1 = q 1 conj / q norme
Cela peut être considéré comme une «division de gauche». La division droite, ce qui n'est pas ce que vous voulez, c'est:
q rot, right = q 2 -1 q 1
la source
Je ne suis pas très bon sur Quaternion. Cependant, j'ai lutté pendant des heures à ce sujet et je n'ai pas pu faire fonctionner la solution Polaris878. J'ai essayé de pré-normaliser v1 et v2. Normaliser q. Normaliser q.xyz. Pourtant, je ne comprends toujours pas. Le résultat ne m'a toujours pas donné le bon résultat.
En fin de compte, j'ai trouvé une solution qui l'a fait. Si cela aide quelqu'un d'autre, voici mon code de travail (python):
Un cas particulier doit être fait si v1 et v2 sont parallèles comme v1 == v2 ou v1 == -v2 (avec une certaine tolérance), où je pense que les solutions devraient être Quaternion (1, 0,0,0) (pas de rotation) ou Quaternion (0, * v1) (rotation de 180 degrés)
la source
quat = diffVectors(v1, v2); assert quat * v1 == v2
.angle
tire sa valeur d'un produit scalaire.Certaines des réponses ne semblent pas envisager la possibilité que le produit croisé soit égal à 0. L'extrait ci-dessous utilise la représentation de l'axe des angles:
Le
toQuaternion
peut être implémenté comme suit:Si vous utilisez la bibliothèque Eigen, vous pouvez également simplement faire:
la source
toQuaternion(axis, ang)
-> vous avez oublié de préciser ce que c'estang
angle
partie de la représentation axe-angle du quaternion, mesuré en radians.Du point de vue de l'algorithme, la solution la plus rapide se présente sous forme de pseudocode
Assurez-vous que vous avez besoin de quaternions unitaires (généralement, il est nécessaire pour l'interpolation).
REMARQUE: les quaternions non unitaires peuvent être utilisés avec certaines opérations plus rapidement que l'unité.
la source