I am working on a Unity game where the Euler angles of the player display some weird behaviour that I cannot understand. There seem to be two full 360 degrees rotations, one positive and one negative. Depending on the direction you go when you are at 0 degrees, it will either take the negative path or the positive path. This means the player can have totally different yaw values depending on if it takes the green or red path. See the following image to get an idea of what is happening:

Player rotation

The issue now comes when I want to calculate the new angle for the player to look at some specific object in the 3d world space. I calculate this angle using some simple math:

// make player the origin, so the target is relative to the player
Vector3 delta = player.angles - target.angles;

float magnitude = delta.Length();

float pitch = asin((delta.y) / magnitude) * (180 / M_PI);
float yaw  = -atan2(delta.x, -delta.z) * (180 / M_PI);

This will give me back correct angles, but the yaw is from 0 to 180, then -180 to 0 again. I correct for this doing:

// this makes sure the calculated angle is from 0-360
if (yaw < 0) {
    yaw += 360; // normalize yaw

So, right now this is aligned with the red rotation line illustrated in the picture above. If I would set the players rotation to the new calculated angle, it would look correctly at the target object directly. But ONLY when the player is on the red rotation path.

If the player for example is on the green rotation path the calculated angle doesn't fit for the current users rotation. If I would set the rotation now, things get quirky. Somehow I need to compensate the calculated new player angle.

What is going on here? and is it possible to manipulate the new calculated angle (which ranges always from 0-360) so it is based on the current players rotation path (either green or red)?

I hope my question makes sense, I found it quite hard to follow what is going on. I hope someone could explain me the situation and ultimately help me out to fix the new calculated angle so it adjusts to the current player rotation path!

Any help is appreciated, thanks in advance!

EDIT So I came up with the following to make sure the player is always rotated the shortest amount, taking both green and red rotation paths into consideration:

// normalize angles for when using negative rotation
if (localAngles[1] < -180)
    angles[1] -= 360;

double diffPitch = (angles[0] - localAngles[0]);
double diffYaw = (angles[1] - localAngles[1]);

// this makes sure we always take the shortest amount of degrees to target
if (diffYaw < -180)
    diffYaw += 360;
if (diffYaw > 180)
    diffYaw -= 360;

I will have to test some more to be sure this is the solution.

  • 2
    \$\begingroup\$ Maybe you've already considered it, but try looking at docs.unity3d.com/ScriptReference/Transform.LookAt.html \$\endgroup\$ – user87553 Feb 28 '17 at 9:43
  • \$\begingroup\$ @OlivierGrech I cannot use Transform.Lookat directly for this, that is why I am calculating this manually. I probably have the solution now, I've edited my post. \$\endgroup\$ – Steffen Brem Feb 28 '17 at 10:48
  • 1
    \$\begingroup\$ This oddness in Euler angles is why a lot of developers prefer to work with rotations as quaternions. It turns out that angular representations are OK for representation a static orientation, but unnecessarily complicated for working with changes in rotation — something quaternions handle quite neatly. I'd highly recommend getting familiar with Unity's quaternion class, as it can greatly simplify a lot of rotation code. \$\endgroup\$ – DMGregory Feb 28 '17 at 13:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.