Reputation: 82
I hope somebody can help. I have a script that rotates a globe, over which a plane (which is stationary) flies from 1 country to another. This all works fine and is achieved with the following script
while (!DestinationReached)
{
Vector3 planetToCountry = (Destination.localPosition - Vector3.zero);//.normalized; //vector that points from planet to country
Vector3 planetToCamera = (camTr.position - tr.position).normalized; //vector that points from planet to camera/plane
Quaternion a = Quaternion.LookRotation(planetToCamera);
Quaternion b = Quaternion.LookRotation(planetToCountry);
b = Quaternion.Inverse(b);
newRotation = a * b;
tr.rotation = Quaternion.Slerp(tr.rotation, newRotation, 0.01f);
if (Approximately(tr.rotation, newRotation, 0.0001f)) //if here the plane has arrived
{
Debug.Log("Destination reached");
DestinationReached = true;
}
yield return new WaitForEndOfFrame();
}
It essentially calculates the angle between the plane (the camera is attached to the plane GO and views it from above) and the destination the globe needs to rotate to so that the plane looks as though it flies to the destination.
The issue I have is I need to make the flight time uniform regardless of the angle the globe must rotate, so lets say it must be 5 seconds, regardless if the plane flies from Paris to Ireland or Paris to Australia. Anybody have any ideas on how to do this.
I have to admit, I nicked this script for the web, as my Vector and Quaternion mathematics is hopeless :)
Upvotes: 0
Views: 37
Reputation: 90580
If you want to be flexible and e.g. add some easing at beginning and end but still finish within a fixed duration I would do it like this (I'll just assume here that your calculating the final rotation is working as intended)
// Adjust the duration via the Inspector
[SerializeField] private float duration = 5f;
private IEnumerator RotateRoutine()
{
// calculate these values only once!
// store the initial rotation
var startRotation = tr.rotation;
// Calculate and store your target ratoation
var planetToCountry = (Destination.localPosition - Vector3.zero);
var planetToCamera = (camTr.position - tr.position);
var a = Quaternion.LookRotation(planetToCamera);
var b = Quaternion.LookRotation(planetToCountry);
b = Quaternion.Inverse(b);
var targetRotation = a * b;
if(duration <= 0)
{
Debug.LogWarning("Rotating without duration!", this);
}
else
{
// track the time passed in this routine
var timePassed = 0f;
while (timePassed < duration)
{
// This will be a factor from 0 to 1
var factor = timePassed / duration;
// Optionally you can alter the curve of this factor
// and e.g. add some easing-in and - out
factor = Mathf.SmoothStep(0, 1, factor);
// rotate from startRotation to targetRotation via given factor
tr.rotation = Quaternion.Slerp(startRotation, targetRotation, factor);
// increase the timer by the time passed since last frame
timePassed += Time.deltaTime;
// Return null simply waits one frame
yield return null;
}
}
// Assign the targetRotation fix in order to eliminate
// an offset in the end due to time imprecision
tr.rotation = targetRotation;
Debug.Log("Destination reached");
}
Upvotes: 1
Reputation: 4283
So the problem here is the t
used on your Quaternion.Slerp
method, it's constant. This t
is the "step" the slerp will do, so if it's contstant, it won't depend on time, it will depend on distance.
Try instead to do something like this, being timeToTransition the time you want that every rotation will match:
public IEnumerator RotatintCoroutine(float timeToTransition)
{
float step = 0f;
while (step < 1)
{
step += Time.deltaTime / timeToTransition;
//...other stuff
tr.rotation = Quaternion.Slerp(tr.rotation, newRotation, step);
//...more stuff if you want
yield return null;
}
}
Edit: addapted to your code should look like this
float timeToFly = 5f;
while (!DestinationReached)
{
step += Time.deltaTime / timeToTransition;
Vector3 planetToCountry = (Destination.localPosition - Vector3.zero);//.normalized; //vector that points from planet to country
Vector3 planetToCamera = (camTr.position - tr.position).normalized; //vector that points from planet to camera/plane
Quaternion a = Quaternion.LookRotation(planetToCamera);
Quaternion b = Quaternion.LookRotation(planetToCountry);
b = Quaternion.Inverse(b);
newRotation = a * b;
tr.rotation = Quaternion.Slerp(tr.rotation, newRotation, step);
if (step >= 1) //if here the plane has arrived
{
Debug.Log("Destination reached");
DestinationReached = true;
}
yield return null();
}
Upvotes: 0