Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

How to get a 360 degree Vector3.Angle?

Discussion in 'Scripting' started by Mirage, Feb 25, 2010.

  1. Mirage

    Mirage

    Joined:
    Jan 13, 2010
    Posts:
    230
    I am creating a flight sim compass and have run into a wall with Vector3.Angle. I have a north angle that I am checking against the transform's rotation in a fixed update. Everything is working fine... except it is returning the angle offset instead of a "polar" offset. If I face 20 degrees left of the angle, it returns 20, thats ok. But when I turn right 20 degrees, it also returns 20. Is there a way to get it to return a value in the entire 360 degree range or is it hardcoded as an offset?
     
    alsiva likes this.
  2. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    Vector3.Angle returns the acute angle between the two vectors. There is some code in this thread that shows how to tell if one vector is to the left or to the right of another. You can get the angle with Vector3.Angle, but if it is to the left, then subtract it from 360 to get the bearing from the forward vector.
     
  3. Mirage

    Mirage

    Joined:
    Jan 13, 2010
    Posts:
    230
    That works perfictly for a fixed rotation user, such as the FPS Player, however I am having trouble converting it to measure only the horizontal vector. My transform is a ship so it's pitch is also a factor. Is there a way to "project" a 3d vector into 2d space, effectivly making the magnitudes irrelelvent? The compass works fine when I use only Roll and Yaw, but when I pull the Pitch up or down it changes the compass value (not good).

    Here are my two scripts. The first script calculates everything, while the second reads it and ouputs the heading into debug.log

    Code (csharp):
    1.  
    2. // This script is named CompassHeading
    3.  
    4. var northMarker : Transform;
    5. static var dirNum: float;
    6. private var heading: Vector3;
    7.  
    8. function Update ()
    9. {
    10.    
    11.      heading.z = (Vector3.Angle(northMarker.position, transform.forward));
    12.     dirNum = AngleDir(transform.forward, heading, transform.up);
    13.  
    14. }
    15.  
    16.  
    17. function AngleDir(fwd: Vector3, targetDir: Vector3, up: Vector3) {
    18.     var perp: Vector3 = Vector3.Cross(fwd, targetDir);
    19.     var dir: float = Vector3.Dot(perp, up);
    20.    
    21.     if (dir > 0.0) {
    22.         return 1.0;
    23.     } else if (dir < 0.0) {
    24.         return -1.0;
    25.     } else {
    26.         return 0.0;
    27.     }
    28. }
    29.  
    Code (csharp):
    1.  
    2. var heading : int;
    3.  
    4. function Update ()
    5. {
    6. // Calculating Heading.
    7.    
    8.    
    9.     if( CompassHeading.dirNum <= 0 )
    10.     {
    11.         heading = (Vector3.Angle(Vector3(0,0,CompassHeading.northOffsetAngle), flyer.forward));
    12.     }
    13.     else
    14.     {
    15.         heading = 360 - (Vector3.Angle(Vector3(0,0,CompassHeading.northOffsetAngle), flyer.forward));
    16.     }
    17.     Debug.Log(heading + "     " + CompassHeading.dirNum);
    18.  
    19. }
    20.  
     
  4. Mirage

    Mirage

    Joined:
    Jan 13, 2010
    Posts:
    230
    5 hours of torment and I finaly figured it out.
    Code (csharp):
    1. heading = parseInt(player.eulerAngles.y);
    2.  
    5 hours of researching Dot Products, Cross Products, Vector Projections and the Physics of 3D Space all for that little bit of code. Turns out Unity had it the whole time. Apparantly something called a Quaternion... Anyway it returns the 360 degree angle between the transform's Y-rotation and 0 degree world space. Everything I needed all contained in one line of code...
     
    npoguca and Edword like this.
  5. FenrirWolf

    FenrirWolf

    Joined:
    Feb 10, 2010
    Posts:
    37
    Another way to do this is to convert the target into local coordinates relative to your object. ie: targetInLocal = transform.InverseTransformPoint (Target)

    If the target is to the left of you, the x axis will be <0, right if its >0. Same goes for above you (y axis) or in front/behind you (z axis).

    But plenty of ways to skin the cat in Unity!

    Mirage: Sometimes it's always the easy solutions that escape our sight in the midst of frustrated coding. :)
     
  6. we rock

    we rock

    Joined:
    Jul 31, 2009
    Posts:
    15
    As Mirage said, the "*.eulerAngles.y" is the exact thing which returns the whole rotation and not just the differentiation.

    Thanks Mirage. I was looking for this... :D
     
  7. ttinywolf

    ttinywolf

    Joined:
    Jun 23, 2014
    Posts:
    5
    Hi,I am very interest in the way to judge one vector is to the left or to the right of another, but the links seems has already broken. Can you please post another one for this topic?
     
  8. IsGreen

    IsGreen

    Joined:
    Jan 17, 2014
    Posts:
    206
    More simple,

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class script1 : MonoBehaviour {
    5.  
    6.     public Transform target;
    7.     public Transform body;
    8.     public string side;
    9.  
    10.  
    11.     void Update () {
    12.  
    13.         if(Vector3.Angle(body.right,target.position-body.position)>90f) side = "left"; else side = "right";
    14.    
    15.     }
    16.  
    17. }
    If angle between right Vector of body transform and target direction is greater than 90, it is left side.
     
    Zombrine and (deleted member) like this.
  9. atr0phy

    atr0phy

    Joined:
    Nov 5, 2014
    Posts:
    43
    Simpler yet, takes same arguments as Vector3.Angle:

    Code (CSharp):
    1.     public static float CalculateAngle(Vector3 from, Vector3 to) {
    2.  
    3.         return Quaternion.FromToRotation(Vector3.up, to - from).eulerAngles.z;
    4.  
    5.     }
    Courtesy of https://gist.github.com/shiwano/0f236469cd2ce2f4f585
     
    PGJ likes this.
  10. Necronomicron

    Necronomicron

    Joined:
    Mar 4, 2015
    Posts:
    108
    For 2D:
    Code (CSharp):
    1.     /// <summary>Calculates angle between 2 vectors. Angle increases counter-clockwise.</summary>
    2.     /// <param name="p1">1st point.</param>
    3.     /// <param name="p2">2nd point.</param>
    4.     /// <param name="o">Starting position of vectors.</param>
    5.     /// <returns>Angle between 0° and 360°.</returns>
    6.     public static float Angle360(Vector2 p1, Vector2 p2, Vector2 o = default(Vector2))
    7.     {
    8.         Vector2 v1, v2;
    9.         if (o == default(Vector2))
    10.         {
    11.             v1 = p1.normalized;
    12.             v2 = p2.normalized;
    13.         }
    14.         else
    15.         {
    16.             v1 = (p1 - o).normalized;
    17.             v2 = (p2 - o).normalized;
    18.         }
    19.         float angle = Vector2.Angle(v1, v2);
    20.         return Mathf.Sign(Vector3.Cross(v1, v2).z) < 0 ? (360 - angle) % 360 : angle;
    21.     }
     
    mahdi_jeddi likes this.
  11. IsGreen

    IsGreen

    Joined:
    Jan 17, 2014
    Posts:
    206
    Useful for 3D/2D(z value equal to 0):

    Code (CSharp):
    1.     float angle360(Vector3 from, Vector3 to, Vector3 right)
    2.     {
    3.         float angle = Vector3.Angle(from, to);
    4.         return (Vector3.Angle(right, to) > 90f) ? 360f - angle : angle;            
    5.     }
    To calculate 360 degree, you need a perspective. For perspective, I use right vector instead up vector.
     
    Last edited: Sep 5, 2016
  12. MikeW138

    MikeW138

    Joined:
    Feb 13, 2019
    Posts:
    1
    LOL you guys take so many time on this. Indeed I just found a fast way
    Code (CSharp):
    1.  
    2.         angle = Vector3.Angle((target.transform.position - myObject.transform.position), myObject.transform.forward);
    3.         float angle2 = Vector3.Angle((target.transform.position - myObject.transform.position), myObject.transform.right);
    4.  
    5.         if (angle2 > 90)
    6.         {
    7.             angle = 360 - angle;
    8.         }
    9.  
     
  13. MrBalin

    MrBalin

    Joined:
    Sep 6, 2014
    Posts:
    8
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class FindDirections : MonoBehaviour
    6. {
    7.     [SerializeField] GameObject Target;
    8.  
    9.     [SerializeField] Vector2 Fwd_MinMax = new Vector2(50f, 140f);
    10.     [SerializeField] Vector2 Side_MinMax = new Vector2(50f, 140f);
    11.  
    12.     enum MyEnum
    13.     {
    14.         Bow,
    15.         Left,
    16.         Right,
    17.         Stern,
    18.         UnAssigned
    19.     }
    20.     MyEnum targetDirection = MyEnum.UnAssigned;
    21.  
    22.     private void Update()
    23.     {
    24.         WhereIsTarget();
    25.     }
    26.  
    27.     void WhereIsTarget()
    28.     {
    29.         Collider myCollider = transform.GetComponent<Collider>();
    30.         Vector2 myColliderCenter = new Vector2(myCollider.bounds.center.x, myCollider.bounds.center.z);
    31.  
    32.         Vector2 target_asV2 = new Vector2(Target.transform.position.x, Target.transform.position.z);
    33.         float angle = Vector2.Angle(Vector2.up, target_asV2 - myColliderCenter);
    34.  
    35.         if(angle <= Fwd_MinMax.x)
    36.         {
    37.             Debug.Log("Target in front");
    38.             targetDirection = MyEnum.Bow;
    39.         }
    40.  
    41.         if(angle > Fwd_MinMax.x && angle < Fwd_MinMax.y)
    42.         {
    43.             float angle_XAxis = Vector2.Angle(Vector2.right, target_asV2 - myColliderCenter);
    44.  
    45.             if(angle_XAxis <= Side_MinMax.x)
    46.             {
    47.                 Debug.Log("Target right");
    48.                 targetDirection = MyEnum.Right;
    49.             }
    50.             if(angle_XAxis >= Side_MinMax.y)
    51.             {
    52.                 Debug.Log("Target left");
    53.                 targetDirection = MyEnum.Left;
    54.             }
    55.         }
    56.  
    57.         if(angle >= Fwd_MinMax.y)
    58.         {
    59.             Debug.Log("Target behind");
    60.             targetDirection = MyEnum.Stern;
    61.         }
    62.     }
    63.  
    64.     private void OnDrawGizmos()
    65.     {
    66.         if(Target != null)
    67.         {
    68.             Vector2 tempColliderCenter = new Vector2(transform.GetComponent<Collider>().bounds.center.x, transform.GetComponent<Collider>().bounds.center.z);
    69.             Vector3 tempPos = new Vector3(tempColliderCenter.x, 0, tempColliderCenter.y);
    70.  
    71.             Gizmos.DrawSphere(tempPos, .3f);
    72.             Gizmos.DrawLine(tempPos, Target.transform.position);
    73.         }
    74.     }
    75. }
    76.  
     
    gareth_untether and senatus like this.
  14. bryanchew1994

    bryanchew1994

    Joined:
    Apr 12, 2023
    Posts:
    11
    Vector3.Angle gives 0-180 degrees

    However, Vector3.SignedAngle gives you -180 to 180,
    so you can get the angle to 360

    if you add 360 to any negative angle values.