- Home /
Quaternion.slerp rotates instantly.
Hi Guys and Gals.
I've a bit of an issue with Quaternion.slerp .. I've been looking around for a while but the solutions that are working for others... don't seem to be working for me, This is what I'm currently doing.
The Expected behaviour is that the unit will rotate, and at the end of it's rotation, fire() the projectile in waiting.
What happens however, is that the unit rotates instantly, waits a period of time (until timeScale is >= 1), and then fires the projectile in waiting.
The problem is , that the Unit shouldn't rotate so fast!
//Rotate Unit(){
void rotateUnit(){
if (rotating == false){
rotateFrom = transform.rotation;
rotateFrom.x = 0f;
rotateFrom.z = 0f;
}
if (timeScale < 1) {
transform.rotation = Quaternion.Slerp (rotateFrom, rotateTo, timeScale / rotateRate );
timeScale = timeScale + Time.deltaTime;
}
if ((timeScale >= 1) && (rotating == true)){
if(this.tag == "Player"){
if(projectileInWaiting != null){
projectileInWaiting.fire();
projectileInWaiting = null;
}
rotating = false;
}
} }
rotateTo is set in another function (with x and z set to 0), and it is rotating to the correct position.
timeScale is reset to 0 when a new rotateTo is determined.
curTurnRate is 1.0f.
rotateRate is equal to (1.0f * curTurnRate).
Thanks in advance to anyone who tries to help :)~ I've written up other questions and found the answer while I was explaining the problem to you all, sadly, this time that was not the case :(
line 10 could just be:
timeScale += Time.deltaTime/theNumberOfSecondsToComplete;
so if you wanted it to take 10 seconds to finish, do:
timeScale += Time.deltaTime/10.0;
thanks, good idea! I've changed it reflect your suggestion :)
Answer by JoBoDo · Apr 21, 2014 at 08:40 AM
Actually, My issue was really simple.
I had a condition to get into this method that rotating had to equal true. Therefore rotateFrom was never set. it was rotating from null to q2. Hence it happening instantly.
I've changed the bool to check whether I should set a new rotateFrom, and my rotations are functioning correctly now. :)
Thanks so much everyone!
Answer by robertbu · Apr 21, 2014 at 08:03 AM
There are two common ways of using Slerp(). The first way has the start and end position fixed, and the third parameter moves from 0.0 to 1.0 over time. The second way to use Slerp is to use some small fraction (usually something like 'Time.deltaTime speed') as the third parameter, and have the first parameter updated with the current rotation each frame. You are mixing the two. That is, you are updating 'rotateFrom' to be the current rotation each time 'rotateUnit()' is called, but you are also varying the third parameter from 0 to 1. As you've seen, this results in a speedup of the rotation. The fix is to not* update rotateFrom after you first set it.
Given the settings, the code should work if you make this fix, but the logic is a bit hinky. In particular, whatever criteria you use for the third parameter of the Slerp() should also be the criteria used on line 12. The only reason that 'timeScale' will work is because 'curTurRate' is 1.0 (and therefore rotateRate is also 1.0). If the value of curTurnRate is changed, the logic on line 12 will fail.
Hi! First of all, thanks for your response. I'll change the conditions for the if statement as per your advice :).
Secondly, when (timescale < 1), rotating will be true. I forgot to mention that but it's how my code is set up elsewhere (The section where I reset timescale to 0 is also where I set rotating = true). So rotateFrom is only being called when it's not currently rotating the unit.
Am I being daft and misinterpreting your response? Or is my code functioning differently to how you thought, thanks again!
The problem is the final criteria for the Slerp(). You have:
timeScale / rotateRate
This value must go from 0.0 to 1.0, so if rotateRate is not 1.0, then then the length of time will change and the criteria for reaching 1.0 will change. For example if 'rotateRate' was 2.0, then 'timeScale' would need to reach 2.0 before the Slerp() would be complete. So if you want to keep that evaluation, then line 12 should be:
if (((timeScale / rotateRate) >= 1) && (rotating == true)){
that helped alot! I've implemented something similar and it works great for me!