x


Problem finding relative rotation from one quaternion to another

I want to find a relative rotation between two quaternions quatA and quatB, i.e. quatC is a quaternion rotation that if applied to quatA would result in quatB. Basically I want something like this:

quatC = Quaternion.RelativeRotation( quatA, quatB );

The only way I can think of to do it is to make two Transforms modA and modB, with modB the child of modA, and use the following code:

modA.rotation = quatA;
modB.rotation = quatB;
quatC = modB.localRotation;

However I would prefer not to use Transforms, and just use quaternions instead.

This previous answer suggests the following code would work:

Quaternion rotationDelta = Quaternion.FromToRotation(modelA.transform.forward, modelB.transform.forward);

But it doesn't appear to work after all, as it only inputs two direction vectors, not rotations. To demonstrate this, attach the following script to a basic cube dragged into an empty scene. The code will position and size the cube.

Modify rotations for models A and/or B. Model C should display the RELATIVE rotation FROM A TO B. In other words, applying C's rotation to A's rotation should result in B's rotation.

Model D shows the ACTUAL result of applying C's rotation to A's rotation. If C showed the actual relative rotation, D would be identical to B. As you will see, this is NOT the case. Hopefully I'm just missing something, but if not, is there a way to get quatC only with code?

var modA : Transform;
var modB : Transform;
var modC : Transform;
var modD : Transform;
var D_Rot_Equals_B_Rot = true;

// Nothing in Start is important to the question, it just sets up
// other objects to help demonstrate the problem
function Start() {
    modA = transform;
    modA.gameObject.name = "Model A";
    modA.position = Vector3(0,0,0);
    modA.rotation = Quaternion.identity;
    modA.localScale = Vector3(.1,.1,.8);
    modB = GameObject.CreatePrimitive(PrimitiveType.Cube).transform;
    modB.gameObject.name = "Model B";
    modB.position = Vector3(1,0,0);
    modB.localScale = Vector3(.1,.1,.8);
    modC = GameObject.CreatePrimitive(PrimitiveType.Cube).transform;
    modC.gameObject.name = "Model C";
    modC.position = Vector3(2,0,0);
    modC.localScale = Vector3(.1,.1,.8);
    modD = GameObject.CreatePrimitive(PrimitiveType.Cube).transform;
    modD.gameObject.name = "Model D";
    modD.position = Vector3(3,0,0);
    modD.localScale = Vector3(.1,.1,.8);
    var bump : Transform;
    bump = GameObject.CreatePrimitive(PrimitiveType.Sphere).transform;
    bump.gameObject.name = "Angle Helper";
    bump.localScale = Vector3(.2,.2,.2);
    bump.position = Vector3(0,.15,-.3);
    bump.parent = modA;
    bump = GameObject.CreatePrimitive(PrimitiveType.Sphere).transform;
    bump.gameObject.name = "Angle Helper";
    bump.localScale = Vector3(.2,.2,.2);
    bump.position = Vector3(1,.15,-.3);
    bump.parent = modB;
    bump = GameObject.CreatePrimitive(PrimitiveType.Sphere).transform;
    bump.gameObject.name = "Angle Helper";
    bump.localScale = Vector3(.2,.2,.2);
    bump.position = Vector3(2,.15,-.3);
    bump.parent = modC;
    bump = GameObject.CreatePrimitive(PrimitiveType.Sphere).transform;
    bump.gameObject.name = "Angle Helper";
    bump.localScale = Vector3(.2,.2,.2);
    bump.position = Vector3(3,.15,-.3);
    bump.parent = modD;
}

function Update () {

    // Modify rotations for models A and/or B.
    // Model C should display the RELATIVE rotation FROM A TO B.
    // In other words, applying C's rotation to A's rotation should result in B's rotation.
    // Model D shows the ACTUAL result of applying C's rotation to A's rotation.
    // If C showed the actual relative rotation, D would be identical to B.
    // As you will see, this is NOT the case.

    modC.rotation = Quaternion.FromToRotation(modA.forward, modB.forward);
    modD.rotation = modA.rotation * modC.rotation;

    if (modD.rotation==modB.rotation) {
        D_Rot_Equals_B_Rot = true;
    } else {
        D_Rot_Equals_B_Rot = false;
    }
}
more ▼

asked Nov 26 '10 at 12:36 PM

robinking gravatar image

robinking
820 66 77 87

(comments are locked)
10|3000 characters needed characters left

1 answer: sort voted first

This should do it:

Quaternion relative = Quaternion.Inverse(a) * b;
more ▼

answered Nov 26 '10 at 12:57 PM

Mike 3 gravatar image

Mike 3
32.4k 17 78 278

Nearly! I tested it both ways and it's actually the other way round - "Quaternion relative = Quaternion.Inverse(a) * b;" works a charm. Thanks! I'll tick this answer, maybe you could update it?

Nov 27 '10 at 05:23 PM robinking

Oh strange, I tested that like 5 times, I must have had a thinko when I wrote it in here. Fixing it now

Nov 27 '10 at 05:50 PM Mike 3

Thanks! It helped me too. I used to have headache from some problem with planets, and had been suffered with that for weeks, and with this solution anything got to work. Thanks again.:)

Mar 30 '12 at 08:44 AM Mahamed9628

Very handy!

Sep 22 '12 at 06:03 AM Favo Yang

Thank you! That took far too long to find X_X

Jul 14 '13 at 05:41 PM Khada
(comments are locked)
10|3000 characters needed characters left
Your answer
toggle preview:

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Topics:

x7840
x3237
x655

asked: Nov 26 '10 at 12:36 PM

Seen: 5791 times

Last Updated: Feb 06 at 07:36 PM