Search Unity

Quaternion math on transform.rotation works, but not on a Quat directly

Discussion in 'Scripting' started by techmage, May 23, 2021.

  1. techmage

    techmage

    Joined:
    Oct 31, 2009
    Posts:
    2,133
    So right now I am doing this:
    Code (CSharp):
    1. transform.localRotation = MathUtility.RotateQuaternion(transform.localRotation, vector2.x, vector2.y);
    and it works perfectly. But if I do this:
    Code (CSharp):
    1. testQuat = MathUtility.RotateQuaternion(testQuat, vector2.x, vector2.y);
    2. transform.localRotation = testQuat;
    It just goes nuts, produces quat values in the thousands, and going to NaN.

    I don't understand why. I know when you call transform.rotation = you are setting the quat on the transform directly and it goes down through a native code path, so it is doing more. But I would really like to understand what more it is doing, and WHY the same code works to rotate transform.localRotation but not a quat by itself.

    I assume transform.rotation is doing to some kind quat value check, or something extra. I would really like to know what that is. Also would like to know what the code is to properly rotate a quat like this.

    Also here is my RotateQuaternion method:

    Code (CSharp):
    1.     public static class MathUtility
    2.     {
    3.         public static Quaternion RotateQuaternion(Quaternion quaternion, float x, float y)
    4.         {
    5.             Quaternion rotateX = Quaternion.AngleAxis(-y, quaternion * Vector3.right);
    6.             Quaternion rotateY = Quaternion.AngleAxis(x, quaternion * Vector3.up);
    7.             quaternion = Rotate(quaternion, rotateX);
    8.             quaternion = Rotate(quaternion, rotateY);
    9.             return quaternion;
    10.         }
    11.  
    12.         public static Quaternion Rotate(Quaternion quaternion, Quaternion rotation)
    13.         {
    14.             quaternion *= Quaternion.Inverse(quaternion) * rotation * quaternion;
    15.             return quaternion;
    16.         }
    17.     }
     
  2. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    4,000
    Well, does your "testQuat" represent a valid Quaternion before you call your "RotateQuaternion" method? If not the result will indeed be garbage. Unity's rotation properties (.rotation or .localRotation) will ensure that the quaternion is normalized and valid..

    Apart from that your "Rotate" method makes no sense at all. You're doing

    q = q * q' * r * q


    Since
    q
    and
    q'
    cancel each other you're just left over with

    q = r * q


    Which is the correct way to rotate the quaternion "q" by the quaternion "r". So I don't really get the point of that "Rotate" method as the normal multiply operator does this already. So your method may look like this instead:

    Code (CSharp):
    1. public static Quaternion RotateQuaternion(Quaternion quaternion, float x, float y)
    2. {
    3.     Quaternion rotateX = Quaternion.AngleAxis(-y, quaternion * Vector3.right);
    4.     Quaternion rotateY = Quaternion.AngleAxis(x, quaternion * Vector3.up);
    5.     return rotateY * rotateX * quaternion;
    6. }
    Though again your main issue is most likely that your original quaternion is not a valid unit quaternion and therefore does not represent a valid rotation.