How to interpolate a rotation to the nearest angle / Smooth Free Axis Third Person

Hi, after searching this on internet a lot i couldn’t find a clear answer to my need. So, as other people may have the same problem, i am sharing here!

Basically, you can’t get it to work with a single range. Visualize below:

As you can see, we have two “walls” but thanks god they are not in the same place! We just have to switch between them.

Put it in practice:

You have the “from” rotation, but this from rotation is not defined, so let just make sure to keep in a 360º range using a modulo (% 360).

And then, you have the “to” rotation. What you need to do here is to take the difference from this rotations.

The difference will be used to “detect” whether the rotation is too far from another (more than 180º). And if this is true, you just change this range to a -180, 180 range.

If in your engine the range is between 0-360 you will keep this, and change to -180-180 when needed.

In Armory, the range is from -180 - 180 // -PI to PI to be more accurate.

In code:

angle1 = (from - 360) % 360; // angle1 is just the "from" angle normalized to be in a 360 range. We don't want to deal with bigger numbers.

difference = (to - angle1) % 360; // also the difference is normalized, because the angle "to" also may be a big value.

if (difference > 180) difference -= 360; // this is responsible to change the -180 - 180 range to a 0-360 range if the difference is greater than 180 degrees.

interpolatedAngle = angle1 + difference * Time.realDelta; // the interpolated angle ready to apply. The difference is gradually reduced, to control the speed just multiply it by another number.

For radians just create two variables in the top of the script and replace them in the code:

rad = Math.PI; // for 180
rad2 = Math.PI * 2; // for 360

Thanks to earlin that shared this method here: https://gist.github.com/shaunlebron/8832585#gistcomment-3227412 and also to Unity guy that write it :slight_smile:

5 Likes

Alternatively, two “walls” are 2 directions where, for example, a player or an object should be looking. As a result, we have 2 vectors, and now we need to find the angle between the vectors:

The (directed) angle from vector1 to vector2 can be computed as
angle = atan2(vector2.y, vector2.x) - atan2(vector1.y, vector1.x);
and you may want to normalize it to the range [0, 2 π):
if (angle < 0) { angle += 2 * M_PI; }
or to the range (-π, π]:
if (angle > M_PI) { angle -= 2 * M_PI; }
else if (angle <= -M_PI) { angle += 2 * M_PI; }

Link: https://stackoverflow.com/questions/21483999/using-atan2-to-find-angle-between-two-vectors

Thus, we get the rotation value, and the value can be interpolated through any functions (lerp, tweening and others) depending on the task.

6 Likes