- Home /
Slerp Rotation Problem
I'm experiencing an issue with Quaternion.Slerp
Click this to watch: This video shows whats occurring with the game.
Here is the code im having an issue with:
public Vector3 newBreakerRotation = new Vector3(0, 0, 0);
public bool bRotating;
public float preRotate;
public float BreakerRotSpeed = 5f;
void Start() {
newBreakerRotation = transform.eulerAngles;
}
void Update() {
float rotate = Input.GetAxis("Rotate");
if (!bRotating) {
if ((rotate > 0f || rotate < 0f) && rotate != preRotate) {
//Code that manipulates the value of newBreakerRotation.
//If Q is pressed, the rotation's z axis is decreased by 90.
//If E is pressed, the rotation's z axis is increased by 90.
bRotating = true;
}
}
if (transform.eulerAngles != newBreakerRotation) {
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Euler(newBreakerRotation), BreakerRotSpeed * Time.deltaTime);
}
else {
bRotating = false; // This never gets called. Why?
}
}
Why doesn't bRotating = false;
get called ever?
Thank you!
Answer by Hoeloe · Oct 14, 2013 at 06:49 AM
Equality testing with floating point arithmetic is always a bad idea. Floating point values (that's anything marked float
or double
, including the fields of Vectors and Quaternions) are notoriously inaccurate. Because of the way they are represented in the computer, they accumulate errors over time. These errors are usually not noticeable, but they do cause equality testing to fail. For example, you might be testing if a number is equal to 0.5, but over time, the errors accumulated means the number is actually 4.9999998721. This difference is so small it is unnoticeable to the naked eye, but these two values are not equal, so equality testing will fail.
So, what can you do to solve this? Well, it's actually quite simple - use a margin of error, instead of an equality test. So rather than writing:
transform.eulerAngles != newBreakerRotation
Try something like this:
(transform.eulerAngles - newBreakerRotation).sqrMagnitude > 0.0001f
(Note that I'm using the square of the magnitude here, not the magnitude, for performance reasons - it saves on a costly square root call.)
You can tweak the value 0.0001f however you like. The smaller it is, the more accurate your results will be, but making it too small will cause your issue to reoccur. Making it larger will cause your rotation to stop early, but a value like 0.0001, or even 0.001, should be sufficient for good results. If you really want to to be accurate, you can also add a clause to snap the rotation to the desired value once you detect the difference to be below the margin of error.
Thank you for your answer. However, did this and it did not resolve my issue. I played with the float value comparison against sqr$$anonymous$$agnitude, it didn't help.
Any other ideas?
Your code says this, line 14
if (rotate != preRotate && rotate != 0)
Edit: just in case you misconstrued, I waan't telling you to try this, I was saying it is the same as this. Adding this in just in case.
I did, but then I also told you to do the same for all floating point comparison, of which you still have 2 more: (rotate > 0f || rotate < 0f)
and rotate != preRotate
I feel I should point out that you STILL are using an equality check with floats, when checking rotate. The only reason this works correctly is because Unity has the margin of error built-in (to set the value to 0 if it's below a threshold), but it's worth noting that ANY floating point comparison (except in specific cases like this) should be done with a margin of error.
Answer by meat5000 · Oct 14, 2013 at 07:55 AM
BreakerRotSpeed * Time.deltaTime
This term does not scale between 0 and 1 with time. Slerp will not slerp
Hoeloe is spot on in the reason why it never reaches the 'else'
It will lerp, because the start value is changed every frame. It won't be slerp, strictly, as it will have extra easing, but it will work.
I say scale as moving t between 0 and 1 scales the lerps return value between from and to.
Yep I see it now Hoeloe, urgh its one of those ^ ^
@Hoeloe Do you know of a particular term for using a Lerp function this way? It's Lerp but not as we know it. Care to coin one?
I'd call it something like "Eased Lerp", "Smoothed Lerp" or "Exponential Lerp", since those all describe the effect you get quite nicely.
Your answer
Follow this Question
Related Questions
Quaternion Rotation Smooth 1 Answer
Multiple Cars not working 1 Answer
My Quaternion rotation happens instantly 0 Answers
Rotating Armature During Animation 1 Answer
Distribute terrain in zones 3 Answers