Search code examples
c#unity-game-enginerotationquaternions

Unable to create relative Quaternion in Unity3D


I am trying to rotate two Quaternions by the same amount (using the same Quaternion). I have an absoluteRotation and a relativeRotation (relative to its parent), I want to rotate the absoluteRotation towards another Transform's absoluteRotation, and then change the stored relative location as well as the stored absoluteRotation to match again:

void LateUpdate()
{
    Quaternion newAbsRotation = Quaternion.RotateTowards(absRotationChain[0], boneChain[0].rotation, 0.5f);
    Quaternion modX = Quaternion.Inverse(absRotationChain[0]) * newAbsRotation;
    if(newAbsRotation == (absRotationChain[0] * modX)) {
        Debug.Log("Equal!");
    } else {
        Debug.Log("Unequal!");
    }
    absRotationChain[0] = newAbsRotation;
    // absRotationChain[0] = (absRotationChain[0] * modX) // doesn't work
}

However, I am unable to create a relative Quaternion for the rotation between both absolute Quaternions. I've read on multiple sources that it is supposed to be q' = q1-1 * q2, and in fact, the code above never prints out "Unequal!". However, this changes when I replace

absRotationChain[0] = newAbsRotation

with

absRotationChain[0] = (absRotationChain[0] * modX)

which is supposed to be equal. Instead of just producing the same result, the Quaternion iteratively approaches very quickly (during half a second) a (0, 0, 0, 0) Quaternion. If I then also replace the third parameter of the RotateTowards-function (0.5f) with 11f, then my Quaternion becomes (NaN, NaN, NaN, NaN).

I worked for hours on this problem now and can't find the reason for this issue, let alone a solution :(


Solution

  • I finally solved this problem!!

    Obviously Unity has a precision problem with Quaternions.
    First of all the Quaternion == Quaternion comparision I made wasn't really safe and just an approximation (they even wrote it in the docs!). So I found out that both were actually different at a very very insignificant digit. I guess Unity doesn't properly normalize the Quaternions.

    In the end, using

    Quaternion.Euler((absRotationChain[0] * modX).eulerAngles)
    

    proved to be a decent workaround -.-'

    Edit: Oh look, knowing that it is a normalization issue brought me this link from a guy having the same problem: https://gamedev.stackexchange.com/questions/74437/unity-quaternion-rotate-unrotate-error