Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

math - Difference between the two quaternions

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...