- Home /
How to ROTATE an object without slowing the ends (lerp)
I know Linear Interpolation slows down the ends because that's just how it works. However I'm trying to make a character turn to face a point over the course of roughly 0.33 seconds.
I've tried using normalize, Math.smothStep, Lerp, Slerp, Vector3.MoveTo, etc. I have googled this and tried many things but everything has an issue. Some have the smoothing at ends, others are not accurate enough, fast enough, slow enough, etc.
I just want to make my character smoothly rotate and look at a point at a consistent speed
My code right now, in Update() (that slows the ending):
float speed = 5f;
Quaternion rotationToLookAtNode = Quaternion.LookRotation(node.transform.position - this.gameObject.transform.position);
transform.rotation = Quaternion.Lerp(transform.rotation, rotationToLookAtNode, speed * Time.deltaTime);
To get constant speed, change final line of your code above to:
transform.rotation = Quaternion.RotateTowards(transform.rotation, rotationToLookAtNode, speed * Time.deltaTime);
'speed' will then be degrees per second, and you will not get the slowing as you would have with Lerp() or Slerp()...and no need for a timer.
nice , i'll give it a go . thanks should be answer too shouldn it,... :P quite some time, you still alive ?::)))
Answer by Loius · Aug 06, 2014 at 03:45 AM
Slerp (Lerp) from a rotation to a target rotation. What you're doing is rotating from the current rotation to the target rotation, which is constantly getting smaller as you get closer. You need to record the rotation at the time you initiated the rotation, and modify the third argument so it goes 0-1.
IEnumerator RotateTo(Quaternion target) {
Quaternion from = transform.rotation;
for ( float t = 0f; t < 1f; t+= speed*Time.deltaTime ) {
transform.rotation = Quaterion.Lerp(from,target,t);
yield return null;
}
transform.rotation = target;
}
Works almost perfectly, thank you! The only thing that isnt perfect is that this makes it take the same duration to turn, whether turning 10 degrees or 180. So when the unit has to turn completely around, it goes really fast, but if only turning a little, is pretty slow. Is there an easy way to make the turning speed consistent?
You want the object to rotate at "X" degrees per second, so just find how many degrees between target and from and mathify it.
I have no idea if it's easy to find the difference in quaternions. If you use Vector3's for target and from you can just say float degrees = (target - from).magnitude. You can convert the v3's to Quaternion with "Quaternion.Euler(v3)".
The total time of the turn is float totalTime = degrees/degreesPerSecond.
So your final for-loop would look like this:
for ( float t = 0f; t < 1f; t+= Time.deltaTime / totalTime ) {
Works like a charm! Thank you very much :)
To do it with Quaternions, I just converted them to EulerAngles/Vector3s like so:
float degreesToTurn = (Quaternion.ToEulerAngles(to) - Quaternion.ToEulerAngles(from)).magnitude;
Answer by supernat · Aug 06, 2014 at 03:47 AM
Since you are performing the lerp every frame from the current value (transform.rotation), you will be acting on a distance that is shrinking every frame, so you will indeed see the rotation slow as you get closer to the end, because the value you are passing to the sleep for the amount (the speed) will be constant for the most part (yes not really, but it is very close as long as all of your frames are about the same time apart). So let's just assume this rate * time.deltaTime is about 0.5 for simplicity. In the first frame, you slerp to 50% of the full rotation. In the second frame, you slerp 50% of What Remains in the rotation, so you can see as frames continue, you continue to slerp 50%, but the rotation amount becomes smaller and smaller.
To fix this, capture the starting rotation at the beginning and use that as the first parameter every frame. Also, simply slerp from 0.0 to 1.0, which is actually the intended use of the lerp and slerp methods, though many people use them in the way you have to ease in and out, which you don't want. So, in frame 1, pass in 0.0, in frame 2, pass in 0.1, in frame 3, 0.2, etc. for the third parameter to lerp. Also, I would do this in the FixedUpdate, though not necessary, but if you do it in Update, it would require the time.deltaTime correction, so you would increase the third parameter by say rate * time.deltaTime every frame, limiting it to 1.0, where rate is around 2 if you wanted the rotation to be about 3% every frame at 60 hz.
Answer by MagyarPeter · Mar 03 at 05:13 PM
I use this code for homing projecties:
public float rotationSpeed = 200f;
public float speed = 20f;
public Transform followMe;
void FixedUpdate()
{
Quaternion q = new Quaternion();
q.SetLookRotation(followMe.position - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation,q, 1f / Quaternion.Angle(transform.rotation, q) * Time.fixedDeltaTime * rotationSpeed);
transform.position += transform.rotation * Vector3.forward * speed * Time.fixedDeltaTime;
}