Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between the two quaternions

Tags:

Solved


I'm making a 3D portal system in my engine (like Portal game). Each of the portals has its own orientation saved in a quaternion. To render the virtual scene in one of the portals I need to calculate the difference between the two quaternions, and the result use to rotate the virtual scene.

When creating the first portal on the left wall, and second one on the right wall, the rotation from one to another will take place in only one axis, but for example when the first portal will be created on the floor, and the second one on the right wall, the rotation from one to another could be in two axis, and that's the problem, because the rotation goes wrong.

I think the problem exists because the orientation for example X axis and Z axis are stored together in one quaternion and I need it separately to manualy multiply X * Z (or Z * X), but how to do it with only one quaternion, (the difference quaternion)? Or is there other way to correct rotate the scene?

EDIT:

Here on this picture are two portals P1 and P2, the arrows show how are they rotated. As I am looking into P1 I will see what sees P2. To find the rotation which I need to rotate the main scene to be like the virtual scene in this picture I'm doing following:

  1. Getting difference from quaternion P2 to quaternion P1
  2. Rotating result by 180 degrees in Y axis (portal's UP)
  3. Using the result to rotate the virtual scene

This method above works only when the difference takes place in only one axis. When one portal will be on the floor, or on te ceiling, this will not work because the difference quaternion is build in more than one axis. As suggested I tried to multiply P1's quaternion to P2's quaternion, and inversely but this isn't working.

enter image description here

EDIT 2:

To find the difference from P2 to P1 I'm doing following:

Quat q1 = P1->getOrientation(); Quat q2 = P2->getOrientation();  Quat diff = Quat::diff(q2, q1);  // q2 * diff = q1 // 

Here's the Quat::diff function:

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)); } 

Conjugate:

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

Dot product:

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; } 

Operator*:

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; } 

Operator/:

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); } 

All this stuff works, because I have tested it with GLM library

like image 907
Tom Avatar asked Mar 03 '14 21:03

Tom


People also ask

How do you subtract two quaternions?

Quaternions are a kind of matrix (a 1x4 matrix containing complex numbers). To append (or add) a matrix, you use matrix multiplication. There is no 'remove/subtract' a matrix. But you can get the effective result by appending the inverse of a matrix.

How do you find the difference between two rotations?

Using rotation matrices¶ The difference rotation matrix that represents the difference rotation is defined as R ≜ P Q ∗ . The distance between rotations represented by rotation matrices P and Q is the angle of the difference rotation represented by the rotation matrix R = P Q ∗ .

How do you find the angle between two quaternions?

So, let us consider the two quaternions q1 and q2... the angle between them (ang) is given by the following relation: q1(inner)q2 = norm(q1)norm(q2)cos(ang). ang = acos{[q1(inner)q2] / [norm(q1)norm(q2)]}.


1 Answers

If you want to find a quaternion diff such that diff * q1 == q2, then you need to use the multiplicative inverse:

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) 

If your quaternions are rotation quaternions, they should all be unit quaternions. This makes finding the inverse easy: since abs(q1) = 1, your inverse(q1) = conjugate(q1) can be found by just negating the i, j, and k components.


However, for the kind of scene-based geometric configuration you describe, you probably don't actually want to do the above, because you also need to compute the translation correctly.

The most straightforward way to do everything correctly is to convert your quaternions into 4x4 rotation matrices, and multiply them in the appropriate order with 4x4 translation matrices, as described in most introductory computer graphics texts.

It is certainly possible to compose Euclidean transformations by hand, keeping your rotations in quaternion form while applying the quaternions incrementally to a separate translation vector. However, this method tends to be technically obscure and prone to coding error: there are good reasons why the 4x4 matrix form is conventional, and one of the big ones is that it appears to be easier to get it right that way.

like image 115
comingstorm Avatar answered Oct 18 '22 17:10

comingstorm