Vector2.SignedAngle backwards?

I have a hard time understanding why Vector2.SignedAngle(new Vector2(0, 1f), new Vector2(1, 0f)) returns -90;
This seems to assume +y is down but in the x/y plane of Unity y is up. So why is this?

Even worse if you write it as Vector2.SignedAngle(Vector2.up, Vector2.right) - how does that make sense?

No comment on this?

I’ve pointed it out before .

The “solution” is to use Vector3.SignedAngle, and provide the correct “up” axis for your vectors (ie. Vector3.back).

1 Like

OK, good. But I would say the solution is just -Vector2.SignedAngle, but why unity?!

Because this way positive rotation angle becomes counterclockwise. It should not be a surprise to unity users because rotating object using inspector gives the same result. Positive angle is counterclockwise for any axis.

It is not a surprise for 3d but for 2d x/y maths it is, however given sprites and RectTransforms do not even pretend to be 2d for rotation perhaps it is to be expected

They just ignore Z coordinate and use canvas hierarchy for rendering order. RectTrasform is based on Transform and they using same matrices and coordinate system.

It is surprising to Unity users that read the docs for signed angle that very specificly states that it uses a clockwise angle:

I’ve delivered a bug report, but I’m pretty sure that it’s the docs that are wrong here. Also note that it states that the angle is acute, and between -180 and 180, which is also just plain wrong.

Both implementations are valid, but the docs shouldn’t state the opposite of what the implementation is! It should also probably know what the maths terms it uses mean!

If starting from scratch, I would’ve implemented this as a clockwise angle - it makes very little sense to look at a clock sprite from the front, and say that the angle from 12 o’ clock to 3 o’ clock is -90. I don’t think it’s worth the breakage that would ensue if the function got “fixed”, though, so the docs should just be fixed instead.

2 Likes

The docs still say it’s clockwise. I ran into this thread exactly because I read them first and then discovered that it’s not doing the expected thing and went searching for answers.

Well, it’s true that the docs are wrong. However the normal mathematical definition is counter clockwise. All trig functions are based on counter clockwise rotation and 0° are usually the positive x axis. In the case of SignedAngle we specify the reference ourselfs. So doing “Vector2.SignedAngle(Vector2.up, Vector2.right)” it should return -90 since that’s a clockwise rotation.

You get the same behaviour from Atan2 which can be used to get the angle between the positive x axis and your given vector. So Mathf.Atan2(v.y, v.x) * Mathf.Rad2Deg is comparable to SignedAngle(Vector2.right, v); for a given vector v.

See Rotation (wikipedia) for more information. To quote:

See also Clockwise (wikipedia). or Euler’s formula(wikipedia). Literally everything related to rotations in math is based on a counter clockwise rotation.

This is an interesting point and some libraries use 0 as right but I feel like that is more the hard-maths community and most developers use a compass-style angle system. But I wonder on the stats…

This method burned me + lost me two dev days. I spent a long time troubleshooting around it thinking that something was off with my algorithm, well it was this function in there.

I swapped to using a

Quaternion.Inverse(transform.rotation) * vec2Direction

and it was more clear to me how to use that output.

There is a high probability that I was using the wrong method in the first place.