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!
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
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.