web-dev-qa-db-fra.com

Différence entre les deux quaternions

Résolu


Je crée un système de portail 3D dans mon moteur (comme le jeu Portal). Chacun des portails a sa propre orientation enregistrée dans un quaternion. Pour rendre la scène virtuelle dans l'un des portails, je dois calculer la différence entre les deux quaternions et le résultat utilisé pour faire pivoter la scène virtuelle.

Lors de la création du premier portail sur le mur de gauche et du second sur le mur de droite, la rotation de l'un à l'autre aura lieu dans un seul axe, mais par exemple lorsque le premier portail sera créé au sol et le second sur le mur de droite, la rotation de l'un à l'autre pourrait être en deux axes, et c'est le problème, car la rotation va mal.

Je pense que le problème existe parce que l'orientation par exemple X axe et Z axe sont stockées ensemble dans un quaternion et j'en ai besoin séparément pour multiplier manuellement X * Z (ou Z * X), mais comment le faire avec un seul quaternion, (la différence quaternion)? Ou existe-t-il un autre moyen de corriger la rotation de la scène?

MODIFIER:

Ici sur cette photo se trouvent deux portails P1 et P2, les flèches indiquent comment ils sont tournés. Pendant que je regarde P1, je verrai ce que voit P2. Pour trouver la rotation dont j'ai besoin pour faire pivoter la scène principale pour être comme la scène virtuelle dans cette image, je fais ce qui suit:

  1. Différence entre le quaternion P2 et le quaternion P1
  2. Résultat de rotation de 180 degrés dans l'axe Y (UP du portail)
  3. Utilisation du résultat pour faire pivoter la scène virtuelle

Cette méthode ci-dessus ne fonctionne que lorsque la différence a lieu dans un seul axe. Lorsqu'un portail sera au sol ou au plafond, cela ne fonctionnera pas car le quaternion de différence est construit sur plusieurs axes. Comme suggéré, j'ai essayé de multiplier le quaternion de P1 en quaternion de P2, et inversement, mais cela ne fonctionne pas.

enter image description here

EDIT 2:

Pour trouver la différence de P2 à P1, je fais ce qui suit:

Quat q1 = P1->getOrientation();
Quat q2 = P2->getOrientation();

Quat diff = Quat::diff(q2, q1);  // q2 * diff = q1 //

Voici la fonction Quat :: diff:

GE::Quat GE::Quat::diff(const Quat &a, const Quat &b)
{
    Quat inv = a;
    inv.inverse();
    return inv * b;
}

Inverse:

void GE::Quat::inverse()
{
    Quat q = (*this);
    q.conjugate();
    (*this) = q / Quat::dot((*this), (*this));
}

Conjuguer:

void GE::Quat::conjugate()
{
    Quat q;
    q.x = -this->x;
    q.y = -this->y;
    q.z = -this->z;
    q.w = this->w;

    (*this) = q;
}

Produit scalaire:

float GE::Quat::dot(const Quat &q1, const Quat &q2)
{
    return q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w;
}

Opérateur*:

const GE::Quat GE::Quat::operator* ( const Quat &q) const
{
    Quat qu;
    qu.x = this->w*q.x + this->x*q.w + this->y*q.z - this->z*q.y;
    qu.y = this->w*q.y + this->y*q.w + this->z*q.x - this->x*q.z;
    qu.z = this->w*q.z + this->z*q.w + this->x*q.y - this->y*q.x;
    qu.w = this->w*q.w - this->x*q.x - this->y*q.y - this->z*q.z;
    return qu;
}

Opérateur/:

const GE::Quat GE::Quat::operator/ (float s) const
{
    Quat q = (*this);
    return Quat(q.x / s, q.y / s, q.z / s, q.w / s);
}

Tout cela fonctionne, parce que je l'ai testé avec la bibliothèque GLM

14
Tom

J'ai résolu mon problème. Il s'est avéré que je n'ai besoin d'aucune différence entre deux rotations. Multipliez simplement une rotation par rotation à 180 degrés, puis multipliez de cette façon par l'inverse de la deuxième rotation (en utilisant des matrices):

Matrix m1 = p1->getOrientation().toMatrix();
Matrix m2 = p2->getOrientation().toMatrix();
Matrix model = m1 * Matrix::rotation(180, Vector3(0,1,0)) * Matrix::inverse(m2);

et traduction calculant ainsi:

Vector3 position = -p2->getPosition();
position = model * position + p1->getPosition();
model = Matrix::translation(position) * model;
4
Tom

Si vous voulez trouver un quaternion diff tel que diff * q1 == q2, Alors vous devez utiliser l'inverse multiplicatif:

diff * q1 = q2  --->  diff = q2 * inverse(q1)

where:  inverse(q1) = conjugate(q1) / abs(q1)

and:  conjugate( quaternion(re, i, j, k) ) = quaternion(re, -i, -j, -k)

Si vos quaternions sont des quaternions de rotation, ils doivent tous être des quaternions unitaires. Cela rend la recherche de l'inverse facile: puisque abs(q1) = 1, votre inverse(q1) = conjugate(q1) peut être trouvée en annulant simplement les i, j et k Composants.


Cependant, pour le type de configuration géométrique basée sur la scène que vous décrivez, vous ne voulez probablement pas faire ce qui précède, car vous devez également calculer la traduction correctement.

La façon la plus simple de tout faire correctement est de convertir vos quaternions en matrices de rotation 4x4 et de les multiplier dans l'ordre approprié avec des matrices de traduction 4x4, comme décrit dans la plupart des textes d'introduction à l'infographie.

Il est certainement possible de composer des transformations euclidiennes à la main, en gardant vos rotations sous forme de quaternion tout en appliquant les quaternions progressivement à un vecteur de traduction séparé. Cependant, cette méthode a tendance à être techniquement obscure et sujette à des erreurs de codage: il y a de bonnes raisons pour lesquelles la forme matricielle 4x4 est conventionnelle, et l'une des plus importantes est qu'il semble plus facile de faire les choses correctement.

28
comingstorm

Les quaternions fonctionnent de la manière suivante: le référentiel local est représenté par les directions imaginaires des quaternions i, j, k. Par exemple, pour un observateur debout dans la porte d'entrée 1 et regardant dans la direction de la flèche, la direction i peut représenter la direction de la flèche, j est vers le haut et k = ij pointe vers la droite de l'observateur. En coordonnées globales représentées par le quaternion q1, les axes en coordonnées 3D sont

q1*(i,j,k)*q1^-1=q1*(i,j,k)*q1',

où q 'est le conjugué, et pour les quaternions unitaires, le conjugué est l'inverse.

Maintenant, la tâche consiste à trouver un quaternion unitaire q de sorte que les directions q * (i, j, k) * q 'dans la trame locale 1 exprimées en coordonnées globales coïncident avec les directions tournées de la trame 2 en coordonnées globales. De l'esquisse qui signifie avant devient arrière et gauche devient droite, c'est

q1*q*(i,j,k)*q'*q1'=q2*(-i,j,-k)*q2'
                   =q2*j*(i,j,k)*j'*q2'

qui est facilement atteint en égalisant

q1*q=q2*j or q=q1'*q2*j.

Mais les détails peuvent être différents, principalement qu'un autre axe peut représenter la direction "vers le haut" au lieu de j.


Si le système global de l'esquisse est à partir du bas, de sorte que global-i pointe vers l'avant dans la direction verticale, global-j vers le haut et global-k vers la droite, alors local1- (i, j, k) est global- ( -i, j, -k), donnant

q1=j. 

local2- (i, j, k) est global - (- k, j, i) qui peut être réalisé par

q2=sqrt(0.5)*(1+j), 

puisque

(1+j)*i*(1-j)=i*(1-j)^2=-2*i*j=-2*k and 
(1+j)*k*(1-j)=(1+j)^2*k= 2*j*k= 2*i

La comparaison avec les valeurs réelles de votre implémentation indiquera la manière dont l'affectation des axes et des directions du quaternion doit être modifiée.

1
Lutz Lehmann

Non, vous devez multiplier deux quaternions ensemble pour obtenir le quaternion final que vous désirez.

Disons que votre première rotation est q1 et le second est q2. Vous souhaitez les appliquer dans cet ordre.

Le quaternion résultant sera q2 * q1, qui représentera votre rotation composite (rappelez-vous que les quaternions utilisent la multiplication à gauche, donc q2 est appliqué à q1 en multipliant à partir de la gauche)

Référence

Pour un bref tutoriel sur le calcul d'un quaternion unique, reportez-vous à ma réponse précédente de débordement de pile

Éditer:

Pour clarifier, vous rencontriez un problème similaire avec les matrices de rotation et les angles d'Euler. Vous définissez vos transformations sur X, Y et Z, puis les multipliez ensemble pour obtenir la matrice de transformation résultante ( wiki ). Vous avez le même problème ici. Les matrices de rotation et les quaternions sont équivalents dans la plupart des cas pour représenter les rotations. Les quaternions sont préférés principalement parce qu'ils sont un peu plus faciles à représenter (et plus faciles à résoudre pour le verrouillage du cardan)

1
AndyG