How can I use lerp to rotate an object multiple times?

My situation is this:

I have an object whose rotation in Euler angles is (0, 12, 0) and I want to rotate it using a lerp function to eg (3600, 12, 0). That is to say, I want it to rotate around the x axis 10 times.

I want to use lerp because I want to use an animation curve to control the rate of the spin - starting slowly, speeding up, finishing slowly. I can’t use a sin curve or similar ease function as I need something more idiosyncratic, hence an animation curve I can edit. Also the end rotation and duration of the spin are set in code as they vary, so I can’t use an animation. And to make it super complicated, the start rotation also varies!

My first thought was a simple Vector3.lerp between the euler angles, but this doesn’t work - as Unity uses Quaternions internally it comes out wonky at the end.

I then thought I would convert the start and end positions into Quaternion values and slerp between them, but that only rotates once because that’s all that Quaternions can represent.

So now I have this monstrosity:

while (timer < spinTime)
    transform.localRotation = Quaternion.Euler(Vector3.Lerp(startRot, endRot, spinCurve.Evaluate(timer / spinTime)));
    yield return null;
    timer += Time.deltaTime;

Which also doesn’t work because even though the start rotation and end rotation as Euler angles have the same y and z values, when converted to Quaternions they don’t, so it spins around multiple axes.

I also tried manually forming the start rotation value to force the z value to remain as 0:

Vector3 startRot= Quaternion.Euler(transform.localEulerAngles.x, transform.localEulerAngles.y, 0).eulerAngles;

But you guessed it, even though transform.localEulerAngles.z == 0, the startRot this generates does not match this:

Vector3 startRot= Transform.localEulerAngles;

So when the lerp starts it jumps to a different starting position.


Try messing with this free tool that does really fantastic things with animations and movement during runtime:

It is probably one of the most popular assets, and the pro version is pretty cheap:

Solved here:

I solved my problem! Not in a generally applicable way, so probably not too helpful to others, but just in case…

In fact the first thing I tried (Vector3.lerp between the Euler angles) was the correct method. The problem was that I was creating end rotation values based on what I was seeing in the inspector, but when I called transform.localEulerAngles I was getting quite different numbers. As my start values were not what I expected I was getting unwanted results.

My solution is to not get the start values from transform.localEulerAngles, but to deduce what they should be based on the game state, and use that as the initial lerp value. Luckily my project makes this pretty easy as there are not many possible starting positions.

The lesson is that transform.localEulerAngles should be used with caution as it does not provide a predictable result, and it will probably not match what is visible in the inspector.