Search Unity

Calculate Angles between 2 directions in screenspace

Discussion in 'Scripting' started by ManuelCosta, Oct 9, 2019.

  1. ManuelCosta

    ManuelCosta

    Joined:
    Dec 24, 2015
    Posts:
    9
    Hello, I'm having a problem calculating an angle between 2 directions.
    My scene is made of 3D cubes (1x1) and a character.
    I want to calculate the angle between two adjacent cubes in relation to the character transform.forward, in screen-space as illustrated below.


    The cubes are not touching each-other physically, they are separated as you can see in the editor view.
    Anyway, in the 3rd picture (explanation) the dark blue line represents the character's forward vector. This vector is the one I would like to be the origin of the angle calculation (clock-wise).
    The two green dots represent the cubes position (1 and 2).
    The light blue is de direction between two points.
    The pink/magenta line represents the desired calculated angle.

    This is what I got so far:
    I convert each cube position to screen-space:
    Code (CSharp):
    1. Vector2 cube1_2D = camera.WorldToScreenPoint(cube1.position);
    2. Vector2 cube2_2D = camera.WorldToScreenPoint(cube2.position);

    After that I establish the origin using the characters position + its forward direction:
    Code (CSharp):
    1. Vector2 character2D = camera.WorldToScreenPoint(character.position);
    2. Vector2 characterForward2D = camera.WorldToScreenPoint(character.position + (1 * character.forward));
    3.  
    4. Vector2 origin = (characterForward2D - character2D).normalized;

    After that I calculate the direction of the two points:
    Code (CSharp):
    1. Vector2 target = (cube2_2D - cube1_2D).normalized;

    Because of the way unity handles Vector2.Angle(), I use two variables to make the angle go from 0 to 360.
    Code (CSharp):
    1. float sign = target.y >= 0 ? 1 : -1;
    2. float offset = sign >= 0 ? 0 : 360;

    And finally the angle is calculated:
    Code (CSharp):
    1. float angle = Vector2.Angle(origin, target) * sign + offset;

    The result should be 270 but I get 120.
    If somebody can help me with this problem I would appreciate it very much.
     
    Last edited: Oct 9, 2019
  2. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    I'm not sure I follow what you're trying to do with "sign" and "offset". Instead, I suggest you use Vector2.SignedAngle, and then if it's less than 0 add 360.

    I suspect your calculation of "origin" could be simplified. You ultimately just need a direction, not a location, so it should be possible to calculate the result using only character.forward and not character.position. Probably not important, though.

    Also, you should keep in mind that cube.position is probably giving you the 3D center of the cube, but the green dots in your picture correspond to the center of the cube's top face. If you were taking the difference between 2 identical cubes and then converting to screen coordinates, this shouldn't matter, but since you are converting to screen coordinates first and then taking the difference, this could conceivably change your results depending on the camera's perspective.
     
  3. ManuelCosta

    ManuelCosta

    Joined:
    Dec 24, 2015
    Posts:
    9
    Thanks for the reply.
    I experimented a lot before creating this post, including using only the direction forward of the character as the origin direction as you mentioned.
    About the cubes position, the code shown is a simplification of what I'm currently doing. In reality the points used in the calculation are actually gameobjects children of the cube itself located at the surface.

    To be honest I don't think the way I am approaching the problem is very smart. What I want to discover is if the cubes adjacent to the one the character is on are to the left, right, front or back in relation to the character's direction. The problem is that the cubes are adjacent when they appear to be (due to camera direction in orthographic view), they are not really near form each other in 3D.

    So, another approach I did was calculating the angle in 3D between the center of the cube the character is on to each point of contact in the cube (little sphere colliders on each cube. you can see in the editor view in the picture above) and the character's forward. (character is the transform the script is in).

    Code (CSharp):
    1. // calculate angles in 3D foreach link in relation to the player.transform.forward
    2.                         Vector3 currPivot = currPlatform.transform.GetChild(0).position;
    3.                         Vector3 linkDir = contactPoint.transform.position - currPivot;
    4.  
    5.                         float angle = Vector3.SignedAngle(transform.forward, linkDir, transform.up);
    Now the angle given was 269.8 or something. Works well.
    Thanks for pointing out to add 360 to the angle if the value is < zero.
     
    Last edited: Oct 10, 2019