Thursday, July 23, 2015

unity - how to get if a rotation/position has been completed?


I've done an if / else with the final position / rotation plus they never complete, how can I check this? stays like this


https://i.imgur.com/3cQ9AEk.gif


    if(head == false)

cam.transform.position = Vector3.Lerp(cam.transform.position, PosicMin, Time.deltaTime * Speed);
else {
cam.transform.position = Vector3.Lerp(cam.transform.position, PosicMax, Time.deltaTime * Speed);
}
if(head == false)
cam.transform.eulerAngles = Vector3.Lerp(cam.transform.rotation.eulerAngles, RotationMin, Time.deltaTime*Speed);
else {
cam.transform.eulerAngles = Vector3.Lerp(cam.transform.rotation.eulerAngles, RotationMax, Time.deltaTime*Speed);
}

Answer




You're using an exponential ease-out Lerp, which in real numbers never actually reaches completion. Each iteration, it moves a fraction of the remaining distance - always leaving a nonzero fraction left to go. Even in finite-precision floating point, it might not reach the destination value: at a certain point, the incremental displacement can round to less than the precision of the current value, resulting in no further change.


Fortunately, Unity's == comparison operator on Vector3s and Quaternions includes a tolerance range so it will return true when they're almost the same.


The other issue that's going to throw you off is you're trying to interpolate Euler angles. This is almost always a bad idea. The game engine does not store or use Euler angles internally - it computes them on demand from the quaternion internals. That means the output you save in one frame might not match the input you get in the next frame, due to inevitable discontinuities in computing an Euler angle triplet from an orientation. That can be the source of the perpetual jitter in your implementation. And even without that complication, Euler angles do not interpolate well in general:


Animation contrasting smooth quaternion interpolation and tumbling Euler angle interpolation




  • On the left: interpolating rotations with quaternions, we get smooth rotation along the shortest arc to the destination




  • On the right: interpolating rotations with Euler angles results in excessive spinning/tumbling





(See this UnityAnswers post for more details - unfortunately the original source of this animation is no longer available online nor in the Wayback machine, but you can play with an interactive app)


So, we can fix your code like so:


// Adjust for deltaTime correctly, given the non-linear nature of this use of Lerp.
float blend = 1.0f - Mathf.Pow(1.0f - Speed/30f, Time.deltaTime * 30f);

// Select destinations. This way we don't need to repeat our blend / check logic.
Vector3 destinationPosition = head ? PosicMax : PosicMin;
Quaternion destinationRotation = Quaternion.Euler(head ? RotationMax : RotationMin);


// Ease toward the selected destinations.
cam.transform.position = Vector3.Lerp(cam.transform.position, destinationPosition, blend);
cam.transform.rotation = Quaternion.Lerp(cam.transform.rotation, destinationRotation, blend);

// Check whether we're "close enough".
if(cam.transform.position == destinationPosition && cam.transform.rotation == destinationRotation) {
// Arrived!
}


If you want to more precisely control the threshold of what gets to count as "close enough," you can use Vector3.Distance and Quaternion.Angle to compute how far we are from our destinations, and compare those against custom thresholds.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...