# How can I implement smooth rotation from one direction to another?

I'm having a problem with animating rotations with 1Matrix.CreateRotationY() with my basic 3D game. Based on where you click the mouse, I want the 3D object to rotate to that direction and then move.

I am using this to determine the target direction:

float rot = (float)(Math.Atan2(X, Z));


It gives me the correct value, but I am not sure how to handle the rotation animation from current direction to new direction. I've tried a few things, but to no avail.

Do you guys know of any good ways of solving this issue?

• I'm not sure I understand what the actual problem is. Does the turn animation not play? Does the rotation of the unit not change? I think you need to be a bit more specific. – Christian Oct 19 '12 at 14:18
• Ah i'm sorry. I can get the direction in which the unit must face in. I can get it to rotate it left or right. i.imgur.com/kK7cO.png . Check the image, I'm facing X but i've clicked in the y direction. The 3d model should rotate clockwise. but i am not sure how i can do that effectively. Does this help? – Sparky41 Oct 19 '12 at 14:30

## 2 Answers

If I read you correctly, you need some way of animating between the pointing at current angle to pointing at a target angle. I was severely tempted to resort to vectors and dot products to solve this more elegantly, but as the questioner phrased the problem in terms of angles, I figured the solution had better be in terms of angles too.

The (simpler) vector approach is outlined in this answer to a similar question

Most of the code is figuring out whether to move the current angle clockwise(decreasing) or anti-clockwise (increasing). We need to figure out which direction is the shortest route to arrive at targetAngle. This is a simple check, except for the case where both angles are on opposite sides of the x-axis. The question becomes, whether it is shorter to move towards the positive-x-axis or negative-x-axis?

In the code below, making angleInc bigger or smaller will make the animation quicker or slower;

float currentRot; //current angle (direction) of entity
float targetRot; // angle entity SHOULD be at
float angInc=MathHelper.Pi/100.0f; //how much we should turn each frame (adjusts speed of animation)

public void Update(){

//first need to make sure that both angles are in the range -pi to +pi
//if they are outside the range, adjust them accordingly
if(currentRot>MathHelper.Pi) currentRot-=MathHelper.TwoPi;
if(targetRot>MathHelper.Pi) targetRot-=MathHelper.TwoPi;
if(currentRot<-MathHelper.Pi) currentRot=MathHelper.TwoPi-currentRot;
if(targetRot<-MathHelper.Pi) targetRot=MathHelper.TwoPi-targetRot;

//next figure out which direction we should be changing currentAngle
bool increasingAngle=false;  this will be true if currentAngles needs to get bigger and vis-versa

//four cases to consider
//both angles are positive
if(currentAngle>=0 && targetAngle>=0){
if(currentAngle<targetAngle)
increasingAngle=true;
}
//both angles are negative
else if(currentAngle<0 && targetAngle<0){
if(currentAngle<targetAngle)
increasingAngle=true;
}
//both angles are on opposite sides of the x-axis
else{
if(Math.Abs(currentAngle-targetAngle)<MathHelper.Pi){// shorter to go via zero
if(currentAngle<0)
increasingAngle=true;
}
else{ // need to go via ±pi
if(currentAngle >0)
increasingAngle=true;

if(Math.Abs(currentRot-targetRot)< angleInc){// we've (almost) reached our target angle
currentRot=targetRot; //in case we are not *exactly* at the target angle
}
else{ //need to move currentAngle towards targetAngle
//direction to move has been calculated  in the previous section
if(increasingAngle==true)
currentRot+=angInc;
else
currentRot-=angInc;

}

enityRotationMatrix=Matrix.CreateRotationY(currentRot);
}


}

EDIT fixed bugs mentioned in comments below

• Thanks for your reply, this sorted the problem to a degree. i.imgur.com/kK7cO.png Here is the scenario. What is happening is that it's rotating Anticlockwise instead of Clockwise between position x and y. I had this problem before but was unable to successfully solve it. – Sparky41 Oct 19 '12 at 16:27
• That problem is going over the 0, kind of a pain but not unsolvable. What you want to do is check if the distance across the +/- pi line is less than the distance between the two normally. If the former make sure you go toward that boundary and over it rather than blending normally. In your example 2.3 - (-2.3) = 4.6 difference anticlockwise. (3.14 - 2.3) - (-3.14 - -2.3) = 0.84 + 0.84 = 1.68 difference clockwise, so you want to subtract angle instead of add, even though the (2.3 - -2.3) is positive – Lunin Oct 19 '12 at 17:58
• This seems to be the perfect answer! Thank you very much!! – Sparky41 Oct 19 '12 at 22:53
• @Sparky41 Thanks. Sorry I led you astray earlier, I threw up an answer without thinking it through properly. – Ken Oct 19 '12 at 22:56

I wrote a lerp function for angles a while back.

private float AngleLerp(float nowrap, float wraps, float lerp) {

float c, d;

if (wraps < nowrap) {
c = wraps + MathHelper.TwoPi;
//c > nowrap > wraps
d = c - nowrap > nowrap - wraps
? MathHelper.Lerp(nowrap, wraps, lerp)
: MathHelper.Lerp(nowrap, c, lerp);

} else if (wraps > nowrap) {
c = wraps - MathHelper.TwoPi;
//wraps > nowrap > c
d = wraps - nowrap > nowrap - c
? MathHelper.Lerp(nowrap, c, lerp)
: MathHelper.Lerp(nowrap, wraps, lerp);

} else { return nowrap; } //Same angle already

return MathHelper.WrapAngle(d);
}