Search Unity

Multiplying a quaternion "orientation" by a quaternion "rotation (delta)"

Discussion in 'General Discussion' started by T0rp3d0, Apr 16, 2020.

  1. T0rp3d0

    T0rp3d0

    Joined:
    Feb 4, 2018
    Posts:
    31
    Hello all,

    I recently stumbled upon a very neat blog post https://developerblog.myo.com/quaternions/ explaining quaternion use.
    I was following along merrily until reaching the section on "Centering your frame of reference". Specifically, i cant figure out what is meant by
    this second paragraph passage: "once you have your inverted centre and you want to use it to figure out which way the user's arm is pointing, just multiply Current Rotation by Centre to cancel out the difference, giving you an orientation in your desired frame of reference."

    Could someone please offer some insight?
     
  2. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    Most likely what it means is, that you want find local reference, in respect to given point.

    Basically, consider some x axis in this example.
    Your object is on absolute position 35.
    Your absolute reference point is at 0.
    But your new reference is at 40.
    So to calculate local reference of the object, in respect to new reference, you subtract 35 - 40 = -5. Which is "cancelling out".
    Your new local reference is -5. But absolute reference is stil 35.
    Is like having child object in parent object.

    Now if you move local reference from 40 to 60, along with object, object stil is at local reference of -5. But absolute reference is now 45.

    Similar is the case with rotation.
    You grab your object and reference rotations (quaternions).
    You however need an inverse of the reference, to get the local rotation.
    Then multiply together, which is kind of adding of rotations together (just like 35 + (-40) = -5), where reference rotation is "negative". That means by "cancelling out".
     
  3. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,571
    That blog post had some horrifically bad explanations.

    As far as I can tell he's explaining working with their kit/gear/whatever and says to take snapshot of user's orientation and then treat as zero transform. Or how to calculate relative matrix.

    Basically, if you have object A in some coordinate system, and object B in the same coordinate system, you can calculate transform of object B relative to object A. By doing this.

    1. Take matrix of object B.
    2. Take matrix of object A.
    3. Invert matrix of object A.
    4. multiple matrix of object b by inverted matrix of object A.

    That will create your relative transform matrix.

    Same deal as going between world and local coordinate systems.
     
    Almighti3 likes this.
  4. Billy4184

    Billy4184

    Joined:
    Jul 7, 2014
    Posts:
    6,023
    Indeed this article does not do a great job of explaining some things.

    What is meant by 'centre' is probably better termed the 'reference rotation'. After all the idea is to calculate the rotation relative to some reference rotation value, which would be the user having their arm pointed at the screen.

    So let's say the user has their arm pointing up, the relative rotation in euler angles is (-90, 0, 0) i.e. -90 degrees around the x axis.

    But to do it with quaternions, you need to get the current rotation and multiply it by the 'inverted' reference rotation, which basically amounts to subtracting the reference rotation from the current one.

    Hope that helps.
     
  5. T0rp3d0

    T0rp3d0

    Joined:
    Feb 4, 2018
    Posts:
    31
    I thought i had almost grasped it all when the article stated that a quaternion can be treated as both an orientation (reference rotation), and also a rotation delta -i.e. rotation away from the reference rotation.
    Such that if you had quaterions A and B, then A*B should be interpreted as A being the orientation, and B as the rotation "away" from that orientation.
    Do you agree with that?
    If so:
    1) may i assume that your preferred term -"reference rotation", is an initial "orientation" quaternion?
    2) looking at the example in your reply. Are you implying the user's up pointing arm is a (-90,0,0) euler rotation relative to (away from) the "reference rotation" of pointing to the screen? So the "reference rotation" (pointing at the screen) is (0,0,0) here?

    Moreover, is it correct to think that multiplying a quaternion A with another inverted quaternion B, encompasses a "subtraction" operation that gives you the rotation "away" from (relative to) the reference quaternion (orientation) B?
    I may be wrong (please correct me), but i keep thinking about all this in terms of vector math. Where you can find a direction vector relative to an "origin" vector B, by subtracting a vector A from vector B -vector B being the reference position?
     
  6. Billy4184

    Billy4184

    Joined:
    Jul 7, 2014
    Posts:
    6,023
    Yes that's correct. In Quaternion maths, multiplying by the inverse is the equivalent of 'subtracting' the rotation.

    That is to say that if C = A * inverse(B), then C * B = A.

    In other words, multiplying a rotation by the inverse of a second rotation subtracts the second rotation from the first, such that multiplying the result to the second rotation produces the first rotation.
     
  7. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    @godfreyidk as already mentioned, the article is badly written. Or at least badly worded. I suggest read few different articles, to get better concept and different view.

    Besides, apply theory in practice. Try different orientations, rotations and references. See yourself, how things work in practice.
     
  8. T0rp3d0

    T0rp3d0

    Joined:
    Feb 4, 2018
    Posts:
    31
    I appreciated the higher level approach of the article, too bad it's inaccurate as you and others pointed out. Most sources though are downright confusing.
     
  9. T0rp3d0

    T0rp3d0

    Joined:
    Feb 4, 2018
    Posts:
    31
    Thank you @Billy4184, that clears up some of the confusion. I might through another question your way once i run into more trouble, i can only hope that you might come to my aid
     
  10. Billy4184

    Billy4184

    Joined:
    Jul 7, 2014
    Posts:
    6,023
    I don't think it's inaccurate at all, just maybe went too far trying to put it in laymans terms that it obscured the logic behind it.
     
    T0rp3d0 likes this.
  11. T0rp3d0

    T0rp3d0

    Joined:
    Feb 4, 2018
    Posts:
    31
    Have you any experience with configurable joints? All my previous assumptions of quaternions have been absolutely stumped by configurable joints.
    Which sent me looking for ways to convert a quaternion to local/space, and down the rabbit hole i went. I ended at that article, and the rest is history.
     
  12. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,571
    Orientation is a rotation and rotation delta is also a rotation.
    Orientation is rotation from "identity transform"* and delta is rotation from one transform to the next.
    They're numerically the same.

    Quaternion works the same way as matrix. Given orientation A and orientation B, you can calculate rotation R that would transform object from A to B, by multiplying B with inverse of A.

    * Identity transform is orientation where all object axes are aligned with world axis. I.e. localXAxis == globalXAxis, localYAxis == globalYAxis, localZAxis == globalZAxis.
     
    Wattosan, angrypenguin and T0rp3d0 like this.
  13. Billy4184

    Billy4184

    Joined:
    Jul 7, 2014
    Posts:
    6,023
    Unfortunately no.
     
    T0rp3d0 likes this.
  14. T0rp3d0

    T0rp3d0

    Joined:
    Feb 4, 2018
    Posts:
    31
    Okay, well you're in for a treat.
    That matrix bit was nicely put, thanks. I think I've got it now, unless i go off fiddling and get stuck again. Cheers for now.
     
  15. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,571
    The difficult part of quaternions is understanding how they work mathematically and why. There are books on the subject.

    Matrix can be understood intuitively, because in its 3x4 form it stores 4 basis vectors (localXAxis, localYAxis, localZAxis, origin), and even in full 4x4 form it can be visualized easily. (4 input pipes crossing 4 output pipes forming a grid, with a valve controlling flow from input to ouptu on each crossing, where each valve corresponds to matrix element value).

    It doesn't quite work the same way with quaternions.
     
  16. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    Yep. That knowledge can be useful. But are not required for using in Unity.
    I wrote in past quaternions using matrices, for 7 joints manipulator. But Unity does that for us.

    Knowing principles of rotation manipulations (not matrix calculations behind), is good enough, for most Unity needs.
    As I already mentioned, based on given theory of adding and subtracting rotations, I would strongly advise, build simple scene with few objects and give a play with rotations. It will clear so much confusion, based on what we have already discussed here.

    For example (pseudo code):
    Code (CSharp):
    1. tr0.rotation = trA.rotation * trB.rotation ; // adding
    2. tr1.rotation = trA.rotation * quaternion.inverse ( trB.rotation ) ; // subtracting
    3. tr2.rotation = quaternion.inverse ( trA.rotation ) * trB.rotation ; // for curiosity
    Also swap A with B, to find out, this is not giving same results, as in normal math multiplication, when swapping two variable.

    Next thing useful can be, understanding distance vector and combining with rotation.
     
    T0rp3d0 likes this.
  17. GoesTo11

    GoesTo11

    Joined:
    Jul 22, 2014
    Posts:
    604
    I spent a lot of time figuring this out recently. I'm used to using transformation matrices to transform rotations and set coordinate systems like neginfinity was saying. My old head had some difficulties figuring this out. I found the videos by 3Blue1Brown and Jorge Rodriquez to be quite helpful. Jorge's are more from a game perspective and 3Blue1Brown is more from a math perspective. Even with those, I had some difficulty figuring out how to combine rotations and set coordinate systems but in the end it is just multiplying Quaternions by other Quaternions or their inverse. You just need to figure out the correct order to do what you want. Rotating a vector is a little more complicated.
     
  18. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    In fact it isn't.
    In principles
    Code (CSharp):
    1. newEndPosition = rotation * someVector ; // i.e. vector as length of the arm.
    so if rotation as quaternion, is represented by z axis 90 degrees and xyz of vector is 0, 10, 0, so it results with new position of 0, 0, 10

    Here is docs on that subject
    https://docs.unity3d.com/ScriptReference/Quaternion-operator_multiply.html
    And in fact, we can just use Quaternion.AngleAxis, so we don't need to even worry about multiplication.
    Unless we start doing some fancy stuff with it.
     
  19. GoesTo11

    GoesTo11

    Joined:
    Jul 22, 2014
    Posts:
    604
    So how does that relate to this video:


    To rotate a vector, he is multiplying the point on the left by the quaternion and on the right by the inverse. Is Unity just doing this behind the scenes when you multiply a vector by a quaternion?
     
  20. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,571
    Actually this is misleading.

    Rotation of a vector using quaternion requires sandwich product.

    upload_2020-4-17_21-59-29.png
    Code (csharp):
    1. v1 = q * v * qInverse
    Judging by your code, unity apparently abstracts this away and hides it within multiplication operator, which is arguably a bad idea.
     
  21. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    @GoesTo11, @neginfinity

    Unity represents quaternion as Quadruple Notation, which I believe it is correct name (someone correct me if I am wrong).
    That means, it does not expose matrix of 4x4, but instead 1x4 [x,y,z,w].
    Try print it out to console.

    Now, to get position after rotation, you multiply 1x4 matrix by 4x1 matrix, which is quaternion (Quadruple Notation) by position (x, y, z, w), where w = 0.

    Hence
    Code (CSharp):
    1. newEndPosition = rotation * someVector ; // i.e. vector as length of the arm.
    Edit:
    Try that

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public class Test_quaternion : MonoBehaviour
    5. {
    6.     public Transform child ;
    7.     public float distance ;
    8.  
    9.     void Update ()
    10.     {
    11.         child.position = ( transform.rotation * new Vector4 ( distance, 0, 0, 0 ) ) ;
    12.  
    13.         Debug.Log ( "q: " + transform.rotation ) ;
    14.         Debug.Log ( "p: " + child.position ) ;
    15.     }
    16. }
    17.  
    upload_2020-4-17_22-57-44.png

    In DOTS, you can get transformation matrix, where rotation is represented as 3x3 matrix.
    In such approach, you can also calculate position, by multiplying rotation (3x3) with distance vector (3x1).
     
    Last edited: Apr 17, 2020
  22. GoesTo11

    GoesTo11

    Joined:
    Jul 22, 2014
    Posts:
    604
    @Antypodish is just four numbers not a 4x4 matrix. What I was wondering and @neginfinity was suggesting that Unity is performing v' = q * v * q-1 whenever you tell it to multiply a quaternion by a vector3 or vector4.

    DOTS does rotation matrices? How about 4x4 translation matrices? I still might need to convert rotations into euler angle sequences (not Unity's sequence). That might come in handy as I already have Matlab code from my masters.
     
  23. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,571
    Treating quaternion as a matrix is incorrect. ijk rule applies to quaternions, but does not apply to matrices.
    i^2 = j^2 = k^2 = ijk = -1.

    To transform a vector directly using a quaternion you need to do the "sandwich product".
    v1 = q * v * qInverse.

    Unity obfuscates it in second multiplication overload, which is not correct thing to do. By doing that it give impression of it being a matrix, while it is not, an therefore breaks rule of least astonishment.

    See multiplication rules on quaternions on wikiepdia.
    https://en.wikipedia.org/wiki/Quaternion

    And specifically this table:
    upload_2020-4-18_2-12-56.png

    It is an extension of imaginary number algebra. And completely unlike matrix.
     
  24. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    It isn't just four numbers. It is quaternion representation, where xyzw are coefficients. Don't get confused with xyz angles either. When using sin and cos, to calculate quaternions, you don't need inverse quaternion, unless calculating for references, as early in this thread discussed.

    Here is a bit more idea about queternion coefficients.
    Conversion between quaternions and Euler angles
    https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles

    https://forum.unity.com/threads/trivia-q-the-w-in-a-quaternion.2039/

    Transformation is 4x4 matrix. But that consist of rotation 3x3, scale 3 elements,and position 3 elements. Last element typically is one 1. This form what you will see mostly in computer since related topics.

    upload_2020-4-18_1-1-41.png
    http://web.iitd.ac.in/~hegde/cad/lecture/L6_3dtrans.pdf

    You can manipulate using transformation matrix every single vertices. Both in OOP and DOTS.
    But in my experience, it is easier to operate on transformation matrix in DOTS, when comes to whole objects.
    Not that is needed, but is easier accessible I think.

    General about transformation.

    https://en.wikipedia.org/wiki/Transformation_matrix
    https://www3.nd.edu/~pbui/teaching/cse.40166.fa10/slides/Lecture_4_Transformations_and_Matrices.pdf


    Unity sources

    https://docs.unity3d.com/ScriptReference/Matrix4x4.html

    https://docs.unity3d.com/ScriptReference/Matrix4x4.TRS.html

    Translation, Rotation, Scale as component of transform 4x4 matrix.


    Wit appropriate manipulations, yo can even skew shapes

     
  25. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    I could probably agree, if my 7 DOF manipulators wouldn't work, or other Unity scripts :)
    So no, it is not necessary for that approach. Never tried either.

    If also curious, you can see Unity DOTS quaternion library.
    Unity.Mathematics/src/Unity.Mathematics/quaternion.cs
    I may be missing your point, so I am happy if you indicate into that direction.
    I just don't see need for that approach. Or I may get rusty as well.
     
    Last edited: Apr 18, 2020
  26. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,571
    Also this is incomplete:
    In this diagram. a, d, g store xAxis vector of local coordinate system,
    b, e, i store yAxis, c, f, j store zAxis, and l, m, n store position.
    Local scale is determined by manitude of each vector, and not by individual elements.

    This is only valid when p, q, r are zero and s is one.
     
  27. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,571
    *sighs*

    The sandwich product is performed by operator* and is hidden from you. Which obfuscates correct math between the whole thing and gives you false impression of quaternion being a matrix. It is a poor design choice in api.

    Because someone thought that overloading operator is convenient, you now have incorrect knowledge of quaternions.

    You are. You think quaternion is just like a matrix. This is incorrrect.
     
  28. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    I see what you and @GoesTo11 try to convey.
    So I decided to look into Unity.mathematics libraries, looking specifically for multiplication method.
    I meant do something different, but my brain didn't let me to rest on that matter.

    I looked into Unity.Mathematics library. I was looking anything, which references imaginary terms, or related to inverse quaternion.
    While my math class indicates at
    Code (CSharp):
    1. public static float3 mul ( quaternion q, float3 v );
    I seems can not find direct reference. Maybe it is as well hidden? Don't know.

    Neither anything obvious to me, regarding imaginary numbers.
    Not saying they isn't. Just that I can not find it at this point.
    Someone may will have better luck.

    I found in new library,
    src/Unity.Mathematics/quaternion.cs
    Code (CSharp):
    1. public static quaternion inverse(quaternion q)
    But then, I don't see anywhere else, to be used, in math library.

    Anyway, I am too tired now for that ;)
     
  29. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,571
    Chances are this particular calculation is in sealed function, native code, or somehow locked away.

    Try to implement it on your own in code and see what happens.

    One more thing. Remember that by multiplying row matrix with a column matrix (1xN * Nx1) you get... a scalar. A single value. Obviously this is not what happens when "multiplying" quaternion with a vector.
     
  30. GoesTo11

    GoesTo11

    Joined:
    Jul 22, 2014
    Posts:
    604
    @Antypodish Thanks, I'm quite familiar with transformation matrices and euler angles. I've published several articles in biomedical and engineering journals that used these extensively. I did not know that Unity supported transformation matrices.
     
  31. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    Unity supports 4x4 matrices for the usual game engine reason -- the graphics card uses them. Unity tries to abstract it away, but still provides access. For examples, it auto-computes the camera's world-view-projection matrix and applies it, but provides a hook for you to change it. Or, to rotate items in the old 2D GUI system you could supply your own rotation matrix -- Unity simply copied that into the draw call.

    Its use of Quaternions is also standard game stuff. They copied the way current engines were using them. That was a selling point, "Unity does everything in the way you're accustomed to, with this stuff added... ".
     
  32. davidnibi

    davidnibi

    Joined:
    Dec 19, 2012
    Posts:
    426
    Anything that uses gifs from popular sitcoms from the 2010's always makes me want to look elsewhere, you';re not buzzfeed, please stop!
    But his arm animation and others puts the gimbal thing across well. :)

    BTW. I needed help with my university computer science work that involved Quaternions (and euler angles), so I went to a Cambridge taught maths teacher, and he didn't have a clue. :D
     
    T0rp3d0 likes this.
  33. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,571
    Graphic cards does not really require matrices, though.

    In fixed function pipeline times, there were function for setting transforms, but right now the GPU will be perfectly fine if it receives already transformed vertices.

    The reason for matrix is that they're popular choice for combining transforms and are easy enough to understand in implement. As such they'll be default choice even in case of a software renderer.

    Speaking of which, when physics engine became more common, matrices became less popular for actually storing object transform. Unity itself, likely stores it not as a matrix, but as a position vector, local scale vector and orientation quaternion. That's because "localToWorldMatrix" is read only.

    There are reasons for that. Matrix allow skew transforms, and allow transform into a coordinate system where axes are no longer orthogoanl. On top of that it is possible to set 4th column (used to affect W component and implement projection transform) to something other than 0, 0, 0, 1. In all of thsoe scenariso physics engine won't be able to do anything with it.

    Additionally, on top of that, there are situations where standard chaining of local transforms via multiplication (parentTransform * childTransform) is undesirable. For example, this can happen if you want to have stretchy limbs on character, without introducing intermediate bone. position/scale/rotation appraoch in this case would allow different way of constructing transforms for each bone.

    But yeah, for the shader matrix is currently much more convenient form.
     
  34. Sylmerria

    Sylmerria

    Joined:
    Jul 2, 2012
    Posts:
    369
    I have same problem and question.

    I through multiply quaternions was the same than apply rotation 1 and then apply rotation 2 but I don't find same result :/

    Code (CSharp):
    1.            var direct = Quaternion.Euler(new Vector3(45, 45, 45));
    2.            var mul1   = Quaternion.Euler(new Vector3(5, 5, 5)) * Quaternion.Euler(new Vector3(40, 40, 40));
    3.            var mul2   = Quaternion.Euler(new Vector3(40, 40, 40)) * Quaternion.Euler(new Vector3(5, 5, 5));
    4.  
    5.            Debug.Log("Direct " + direct.ToString("R"));
    6.  
    7.            Debug.Log("euler 1 " + mul1.eulerAngles.ToString("R"));
    8.            Debug.Log("euler 2 " + mul2.eulerAngles.ToString("R"));
    9.            Debug.Log("mul1 " + mul1.ToString("R"));
    10.            Debug.Log("mul2 " + mul2.ToString("R"));
    which gives me this result :

    > Direct (0.4619398, 0.191341713, 0.191341713, 0.8446232)
    > euler 1 (40.2630348, 50.744957, 49.2403755)
    > euler 2 (40.2630348, 49.2403755, 50.744957)
    > mul1 (0.450313926, 0.236193061, 0.219346732, 0.8326566)
    > mul2 (0.450313926, 0.219346732, 0.236193061, 0.8326566)

    From your conversation and my understanding, mul2 should be equals to Direct and euler2 equals to (45,45,45), isn't it ?
     
  35. Billy4184

    Billy4184

    Joined:
    Jul 7, 2014
    Posts:
    6,023
    I'm no expert on quaternions, but afaik you can't perform normal vector operations on them. I would suggest testing visually.
     
  36. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,571
    Yes.

    https://docs.unity3d.com/ScriptReference/Quaternion-operator_multiply.html

    However, you're using eauler angles to verify rotation and that is not a god idea. Angle-Axis form is more convenient.

    Nope.

    Basically, with exception of simple cases,
    Euler(a, b, c) + Euler(d, e, f) != Euler(a + d, b + e, c + f).

    So.
    Euler(40, 40, 40) + Euler (5, 5, 5) will not be equal to Euler (45, 45, 45).

    It will work sometimes with two rotations on the same axis, for example:
    Euler(a, 0, 0) + Euler(b, 0, 0)

    But when multiple rotations are involved results become hard to predict.

    Try combining Euler(90, 0, 0) and Euler(0, 90, 0) and see what happens. Especially when you combine them in different order.
     
    Sylmerria likes this.
  37. Sylmerria

    Sylmerria

    Joined:
    Jul 2, 2012
    Posts:
    369
    I see, I have made several try and with your explication I begin to have a better understanding of that, thks
     
  38. Sylmerria

    Sylmerria

    Joined:
    Jul 2, 2012
    Posts:
    369
    You right, my values comparisons as said by neginfinity is sally.
    Using dot of quaternions shows me that quaternion are same