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

This should do it:

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

“quaternion rotation that if applied to quatA would result in quatB” is:

quatB * Quaternion.Inverse(quatA)

Here is how you can check it:

var quatA = Quaternion.Euler(10, 10, 10);
var quatB = Quaternion.Euler(15, 20, 25);
var relative1 = quatB * Quaternion.Inverse(quatA);
var relative2 = Quaternion.Inverse(quatA) * quatB;
var check1 = relative1 * quatA;
var check2 = relative2 * quatA;

Debug.Log(relative1.eulerAngles);
Debug.Log(relative2.eulerAngles);
Debug.Log("check relative1 " + check1.eulerAngles);
Debug.Log("check relative2 " + check2.eulerAngles);

Output:

(7.75, 7.65, 13.43) // Just to show that
(6.75, 8.66, 13.34) // order is important
check relative1 (15.00, 20.00, 25.00) // Correct one, equal to quatB
check relative2 (14.04, 20.95, 24.69)

I tried to use the suggested code, but for some reason the result is always (0,0,0,1) even when there is a difference between the two quaternions as proven by using debug.log. Here’s the code I’m using:

var ThisRot:Quaternion = transform.rotation;
var RotChange:Quaternion =  Quaternion.Inverse(LastRot) * ThisRot;
Debug.Log("LastRot ="+LastRot+" ThisRot="+ThisRot+" RotChange="+RotChange);
LastRot = ThisRot;

Anyone know why this doesn’t work?

[Edit: it turns out that it only seemed it didn’t work because when Debug.Log prints out quaternions there’s a one-digit limit for the fractional value, which means small angles don’t show up.]

I would convert the rotations to Euler Angles, do a Vector3 difference, then convert back to Quaternions. This can be done with .eulerAngles against the transform.rotation and then Quaternion.Euler outside the parentheses enclosing the Vector3 subtraction. To simply get the angle you can do Quaternion.Angle.