Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Quaternion.LookRotation around an axis

Discussion in 'Scripting' started by Risine, Jan 6, 2019.

  1. Risine

    Risine

    Joined:
    Dec 10, 2009
    Posts:
    154
    Hello there,
    I'd like to to get the quaternion between 2 vectors from and to (like LookRotation), while fixing the rotation around a specific axis ( Y ).
    How can it be done?
     
  2. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,992
    Use copies of the vectors with y set to 0. With everything "on the ground", the spin will automatically be flat, around y. If you want to add that to the old spin, newYonlySpin*oldSpin should do it.
     
  3. Risine

    Risine

    Joined:
    Dec 10, 2009
    Posts:
    154
    I dont understand.
    I have :
    from = 0, 0, -1
    to = 0, 0, 1
    up = 0, -1, 0
    if I do : Quaternion.FromToRotation(from, to) * up
    I get : 0,1,0 (because rotation seems to be made around X axis).
    but I want 0, -1, 0 (rotation around Y axis)
     
  4. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,992
    You get a nice y-spin for anything except 180 degrees. But you're right, Unity just feels like doing an "up and over" x-spin for 180(*). There's no way to change that. You can just hand-check "if the angle is almost 180, use (0,180,0) for the rotation". In practice that either never happens, or there are nicer ways depending on exactly your game.

    (*)Bizarrely, printing it (eulerAngles) gives (0,180,180), which is an alternate way to write (180,0,0).
     
  5. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,514
    You could write your own FromToRotation.

    Basically to get the from/to of 2 vectors you set the imaginary portion to the cross product of the 2 vectors, and the real (w) to the scaled dot product of them... and normalize all that for good measure.

    You have to account for when the cross product is a zero vector, meaning they're parallel. If this happens you then need to know if they're opposing or the same. Same is of course no rotation, and opposing is 180 degrees around ANY axis (unity just happens to use x I guess...)

    So allow passing in that vector:
    Code (csharp):
    1.  
    2.         public static Quaternion FromToRotation(Vector3 v1, Vector3 v2)
    3.         {
    4.             var a = Vector3.Cross(v1, v2);
    5.             double w = System.Math.Sqrt(v1.sqrMagnitude * v2.sqrMagnitude) + Vector3.Dot(v1, v2);
    6.             if (a.sqrMagnitude < 0.0001f)
    7.             {
    8.                 //the vectors are parallel, check w to find direction
    9.                 //if w is 0 then values are opposite, and we should rotate 180 degrees around some axis
    10.                 //otherwise the vectors in the same direction and no rotation should occur
    11.                 return (System.Math.Abs(w) < 0.0001d) ? new Quaternion(0f, 1f, 0f, 0f) : Quaternion.identity;
    12.             }
    13.             else
    14.             {
    15.                 return new Quaternion(a.x, a.y, a.z, (float)w).normalized;
    16.             }
    17.         }
    18.  
    19.         public static Quaternion FromToRotation(Vector3 v1, Vector3 v2, Vector3 defaultAxis)
    20.         {
    21.             var a = Vector3.Cross(v1, v2);
    22.             double w = System.Math.Sqrt(v1.sqrMagnitude * v2.sqrMagnitude) + Vector3.Dot(v1, v2);
    23.             if (a.sqrMagnitude < 0.0001f)
    24.             {
    25.                 //the vectors are parallel, check w to find direction
    26.                 //if w is 0 then values are opposite, and we should rotate 180 degrees around the supplied axis
    27.                 //otherwise the vectors in the same direction and no rotation should occur
    28.                 return (System.Math.Abs(w) < 0.0001d) ? new Quaternion(defaultAxis.x, defaultAxis.y, defaultAxis.z, 0f).normalized : Quaternion.identity;
    29.             }
    30.             else
    31.             {
    32.                 return new Quaternion(a.x, a.y, a.z, (float)w).normalized;
    33.             }
    34.         }
    35.  
    I hope I have my math right... I ran some tests, I think it is.
     
  6. Risine

    Risine

    Joined:
    Dec 10, 2009
    Posts:
    154
    Thanks guys for your help, I'll give it a try!