- Home /
How can I Lerp a rotation through "straight up?"
I have a spaceship object with a transform. A second transform is positioned some offset distance away, and then I use LookAt() to aim its forward vector at the ship. The ship's parent is this second transform. To move the ship, I take player input to place a destination object on the sphere. I create a "destination" transform at the center of the sphere, and use Lerp() or RotateTowards() to move the ship over the surface of the sphere, from the player's rotation to the destination rotation.
parentTransform.rotation = Quaternion.Lerp(parentTransform.rotation,
destinationTransform.rotation, Time.deltaTime * speed);
The problem I'm having is when the parent transform needs to Lerp "through the north pole" (or south pole.) Since the forward vector is aimed at the player ship, this trouble spot is when the forward vector is trying to point either straight up or straight down.
Instead of my ship flying smoothly over the pole to arrive at his destination on the other side, he instead rotates around the north pole, and ends up on the other side facing backwards. I have managed to get the ship stuck at the north pole, but flying across it has never worked for me, and all of my attempted solutions have ended in disaster.
My question is, how can I get the desired behavior here? My hope is that this is a known issue with Lerp() and there's an elegant workaround. Any help is appreciated!
Answer by neonblitzer · Jun 03, 2015 at 07:06 PM
The lerping probably works as intended. The problem is that you create the rotations with LookAt
, and the relative up axis is very close to the ship's or target's position which makes small differences in direction affect resulting rotation greatly. You should specify the worldUp
parameter in Transform.LookAt
to be as far away as possible from the ship's and target's positions. You can use, for example, a cross product of the vectors to the ship and the destination to acquire a vector that is at right angle to (90 degrees away from) both of them, and use that as the worldUp
parameter in LookAt
to create the start and end rotations.
...Pretty hard to explain. Please comment if it's still unclear :)
Excellent point. I totally forgot he was using LookAt to find his target rotation. I'd be willing to bet that would solve his problem!
Thanks :) @SocketPop, check out my comment on Sunny's answer too. You might want to rethink your approach, depending on your needs.
Brilliant, thank you so much for this solution. It worked beautifully! Here's a code snippet slightly modified to be clearer, showing how I got it to work with your suggestion.
// Given playerObject (this) and destObject, which have parent
// transforms playerParent and destParent...
// Get the cross product of the two vectors.
Vector3 upVector = Vector3.Cross(playerParent.forward,
destParent.forward);
// Decouple playerObject and destObject transforms from
// their parents. Otherwise, they would be rotated in an
// undesirable way by the upco$$anonymous$$g LookAt()
transform.parent = null;
destObject.transform.parent = null;
// The parent transforms (positioned at the center of the sphere)
// LookAt the two objects again, but with .up perpendicular
playerParent.LookAt(transform.position, upVector);
destParent.LookAt(destObject.transform.position, upVector);
// Reunite playerObject and destObject with their parents.
// So the objects will rotate with the upco$$anonymous$$g Lerp
transform.parent = playerParent;
destObject.transform.parent = destParent;
playerParent.rotation = Quaternion.Lerp(playerParent.rotation,
destParent.rotation, Time.deltaTime * speed);
And yes, after posting this question I then tried a different approach which did not rely on Lerp(). It's not done yet, but if successful I'll post my results here. Thanks again! Even if my alternate approach works, I bet this quirk with Lerp() will come up again and next time I'll be ready!
Answer by AlwaysSunny · Jun 03, 2015 at 07:02 PM
Frankly, I don't follow. I feel like maybe all the necessary information is here to form a clear picture, but it's not translating into a concrete understanding for me. I know it's hard to describe complex scenarios.
A Lerp is a linear interpolation from one quaternion value set to another. It isn't broken or limited in certain conditions; it does exactly what it's supposed to do. The problem must lie in your utilization. In your defense, this stuff can be very confusing.
If I'm understanding, your ship's movement about the surface of a sphere is achieved by rotating the ship around the sphere's origin.
I guess that all makes sense and ought to work, but the problem you are describing does not seem directly related to the selected approach. It also seems like you aren't actually achieving what you're hoping to achieve in the first place. If logic creates an unwanted change in one scenario, it's probably creating the same kind of not-quite-right change in other scenarios, you just aren't noticing. Any chance you're certain I'm wrong, and it only acts funny at the poles?
My first thought is this: You are wanting to achieve this behavior using only a target rotation. That target rotation does not - on its own - represent enough information to give you the results you're seeking.
I would first try to rely on a different method for making the ship "face" the desired destination. Remove that element from the equation altogether and get there in some other way. Besides, to look correct and "hug" the surface, the ship needs to face a direction tangential to the arc described by its motion.
My other thought is this: You may be using an improper method for arriving at the unknown (destinationTransform.rotation) which drives this behavior.
Quaternion representations and extensions are designed for exactly this kind of complex situation. No gimbal lock, no weird edge cases - if you're using them properly, this kind of problem does not manifest.
The target rotation does have enough information, I think. It's just that now the rotations represent both the ships' position and local rotation, so you have to be very exact and careful when creating the rotations. And eventually the two are going to un-sync no matter how careful you are :)
As you suggested, it might be easier in the long run to have the lerping only control the position and orient the ships with a completely different method separately. It enables them to face other directions when moving, for example.
$$anonymous$$arked your answer as correct; realizing how he was getting his target rotation, I'm quite confident injecting a valid normal axis in the LookAt() is gonna fix his problem.
Your answer
![](https://koobas.hobune.stream/wayback/20220613200558im_/https://answers.unity.com/themes/thub/images/avi.jpg)
Follow this Question
Related Questions
How can I smooth the rotation using quaternion and raycast? 1 Answer
Smoothly Rotate 2D sprite 90 degrees on click 2 Answers
Lerping Quaternions Results in NaN's 1 Answer
better way to rotate instead Coroutine 1 Answer
Use Lerp to rotate object 2 Answers