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

How to get angle between vectors per axis

Discussion in 'Scripting' started by Giustitia, Oct 18, 2019.

  1. Giustitia

    Giustitia

    Joined:
    Oct 26, 2015
    Posts:
    113
    Hi everyboy! I've been struggling for days with a problem about Quaternions, vectors and angles. So, I'm trying to get the angle between a random vector and a transform per axis. That means that what I need is the angle between them in X axis and Y axis separately.

    For example, lets imagine a transform which forward is pointing to (0, 0, 1) and a vector pointing to (0.5, 0.7, 0.5). In this case, the expected value would be 45º on X and 45º on Y. How do I get that values?

    Thank you everybody! :)
     
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,773
    You can make copies, set one field to 0 (both X's), then get the angle. Wash, rinse, repeat.
     
  3. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,616
    Have you tried the Vector3.Angle function?
     
  4. Giustitia

    Giustitia

    Joined:
    Oct 26, 2015
    Posts:
    113
    Yep, but this way I get the shortest angle, rotated both on X and Y :/
     
  5. kdgalla

    kdgalla

    Joined:
    Mar 15, 2013
    Posts:
    4,616
    Not sure I understand what you want. So you say:
    When you say per axis, do mean the transform's orientation vectors? So, assuming by the transform's X you mean transform.right and by Y you mean transform.up, can't you just do Vector3.Angle(randomVector, transform.right) and Vector3.Angle(randomVector, transform.up)?

    Did you want the angles projected on the transform's xz plane and xy plane or something like that?
    maybe you want https://docs.unity3d.com/ScriptReference/Vector3.Project.html
     
  6. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    You can get the rotational different between two vectors by using Quaternion.FromToRotation, and then you can break that down into individual axes with the eulerAngles property. All together, that might look something like:
    Code (CSharp):
    1. Quaternion changeInRotation = Quaternion.FromToRotation(myReferenceForwardVector, targetTransform.forward);
    2. Vector3 euler = changeInRotation.eulerAngles;
    Note that there might be more than one possible collection of Euler angles representing the same rotation, and this won't necessarily give you the one you'd expect. If you want something a bit more reproducible, then instead of using the eulerAngles property you could use ToAngleAxis, which will automatically pick an axis that allows the rotation to be expressed as a single angle (note: this "axis" probably won't be aligned with X, Y, or Z).

    Also, I've just noticed that the fact that FromToRotation works with vectors implies that it can only capture pitch + yaw and not roll. To be completely general, I guess you'd express the starting and ending rotation both as Quaternions, and then ask for the Quaternion that rotates between them, which I suppose would be... Quaternion.Inverse(start) * end?
     
  7. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,992
    I think the FromToRotation method is hopeless (but it seems like a good idea). As Anitsone mentions, it really does compute it as an angleAxis style -- a smooth rotation around the axis perpendicular to both vectors. When we translate that into eulerAngles, it basically uses world Z. For example, this seems like it should give (-85,90,0) as the answer (the first arrow is rotated 85 degrees down on x, the second 90 degree on y):

    Code (CSharp):
    1. Vector3 v1, v2;
    2. v1=Quaternion.Euler(85,0,0)*Vector3.forward; // 85 on x
    3. v2=new Vector3(1,0,0); // 90 on y
    4. Debug.Log(Quaternion.FromToRotation(v1,v2).eulerAngles);
    But it really gives (355.0, 5.0, 89.6). It's giving a 5 degree rotation on x and y, which I assume puts it on the xy-plane, with a little +x, then a big 89.6-degree z-spin (on the real +z, swinging the arrow from down to right).

    To put it another way it computes the best rotation using the superior Quaternion system. When we try to translate that into the inferior eulerAngle system, of course we get values that seem wrong. If x&y rotations and quaternions translated easily, we never would have needed quaternions.
     
    jade_unity238 likes this.