• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
1
Question by drizztmainsword · Jun 02, 2012 at 12:04 AM · quaternionlerp

Lerping a Quaternion the long way around

So we all know that Quanternion.Lerp() moves from one rotation to the other over the shortest possible distance.

I would like to know if there is a way to make the Lerp go in the opposite direction.

My initial impulse was to find the rotation at the "halfway rotation" in the lerp (where t = 0.5) between two rotations and then reverse the rotation to face the opposite direction. With this new rotation, I would rotate from my start to that, and then from there to my end, but I have absolutely no idea how to "reverse" the angle of the rotation.

Is what I'm asking even possible?

Comment
Add comment · Show 1
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Wolfram · Jun 02, 2012 at 10:58 AM 1
Share

Haven't tried Quaternion.Lerp() in particular, but for other Lerps, the t value is automatically clamped to [0..1].

4 Replies

· Add your reply
  • Sort: 
avatar image
2
Best Answer

Answer by drizztmainsword · Jun 08, 2012 at 04:08 AM

Okay, I got this to do what I wanted. It might be a bit more annoying to pull off, but it provides that much more customization to my sword swings, so that works out.

What I did is add a third rotation for the midpoint along my path. Then, if I've set up the slash to use that mid rotation, I fire off this bit of code (understand that "lerpTime" is a 0 - 1 float for the lerp).

 if (0.5f >= lerpTime)
     relativeRotation = Quaternion.Lerp(startRotation, midRotation, lerpTime * 2);
 
 else
     relativeRotation = Quaternion.Lerp(midRotation, endRotation, (lerpTime - 0.5f) * 2);

Thus, so long as the difference between startRotation and midRotation and midRotation and endRotation are each less than 180 degrees from each other, the movement looks correct. With a sword slash, this also allows me to incorporate sweeping motions and little flicks that might have otherwise been very difficult to pull off.

I hope this is useful to other folks beside me. I know doing sword slashes through code isn't exactly a broad use case.

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Vicas · Feb 18, 2013 at 08:20 PM 0
Share

I cant see the code here. I have the same issue and would love to know the answer!

avatar image Wolfram · Feb 18, 2013 at 11:51 PM 0
Share

I converted it to Yoda syntax, so that the html parser won't mess it up.

avatar image Elecman · Jul 20, 2015 at 04:19 AM 0
Share

I think it is also worth mentioning that midRotation is calculated like this:

 Quaternion midRotation = Quaternion.Slerp(startRotation, endRotation, 0.5f) * Quaternion.AngleAxis(180f, Vector3.forward);

Set Vector3.forward to your rotation axis.

avatar image
6

Answer by Maeslezo · Jan 26, 2017 at 02:42 PM

I think those solutions are weird or at least not very "quaternion" friendly.

I have written the lerp and slerp myself, with a flag to indicate whether you want to force the short way or not. I am pretty sure that Unity checks that to invert the rotation. With this code, you can indicate if you want that behaviour.

I have checked myself and it seems it works ok, but check yourself just in case:

 public static class QuaternionExtension
 {
     public static Quaternion Lerp(Quaternion p, Quaternion q, float t, bool shortWay)
     {
         if (shortWay)
         {
             float dot = Quaternion.Dot(p, q);
             if (dot < 0.0f)
                 return Lerp(ScalarMultiply(p, -1.0f), q, t, true);
         }
 
         Quaternion r = Quaternion.identity;
         r.x = p.x * (1f - t) + q.x * (t);
         r.y = p.y * (1f - t) + q.y * (t);
         r.z = p.z * (1f - t) + q.z * (t);
         r.w = p.w * (1f - t) + q.w * (t);
         return r;
     }
 
     public static Quaternion Slerp(Quaternion p, Quaternion q, float t, bool shortWay)
     {
         float dot = Quaternion.Dot(p, q);
         if (shortWay)
         {
             if (dot < 0.0f)
                 return Slerp(ScalarMultiply(p, -1.0f), q, t, true);
         }
 
         float angle = Mathf.Acos(dot);
         Quaternion first = ScalarMultiply(p, Mathf.Sin((1f - t) * angle));
         Quaternion second = ScalarMultiply(q, Mathf.Sin((t) * angle));
         float division = 1f / Mathf.Sin(angle);
         return ScalarMultiply(Add(first, second), division);
     }
 
 
     public static Quaternion ScalarMultiply(Quaternion input, float scalar)
     {
         return new Quaternion(input.x * scalar, input.y * scalar, input.z * scalar, input.w * scalar);
     }
 
     public static Quaternion Add(Quaternion p, Quaternion q)
     {
         return new Quaternion(p.x + q.x, p.y + q.y, p.z + q.z, p.w + q.w);
     }
 }
 
Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image fffMalzbier · Feb 28, 2018 at 03:27 PM 0
Share

Super nice for sharing , Works like a charm.

avatar image
1

Answer by Wolfram · Jun 02, 2012 at 12:57 AM

It certainly is. And there is probably also a simpler/better way to do it, but since I'm not a Master of Quaternion, I'd suggest this:

  • find the Quaternion covered by your lerp with Quaternion.FromToRotation(A,B)

  • convert that to Angle/Axis representation with Quaternion.ToAngleAxis(angle,axis)

  • what you now want is to rotate around that axis by angle-360, for example with the help of transform.RotateAround()

Comment
Add comment · Show 6 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image drizztmainsword · Jun 07, 2012 at 09:36 PM 0
Share

Okay, so that totally makes sense, but how do I get those A and B Vector3's?

I tried to jump that step by by using the Inverse of my starting rotation multiplied by my ending rotation as the rotation that, if applied to the start, would end up with the end rotation, but that doesn't give the best results…

I think the fundamental problem is that the rotation isn't just along one axis.

For some more context: I'm using this code as part of a dynamic slashing system for a sword swing. I basically have a starting position and rotation and an ending position and rotation for the sword, and I'm lerping between them. I'm going to add arc code to the position of the sword so that the hand doesn't move in a straight line, but I want the rotation of the sword to be correct before I start using bezier curves.

The problem is that most sword swings are quite wide, thus I need to lerp in the "wrong" direction.

avatar image Wolfram · Jun 07, 2012 at 10:32 PM 0
Share

Hm? A and B are simply the rotation quaternions of your start and end position, for example Quaternion.FromToRotation(source.transform.rotation,target.transform.rotation).

If ins$$anonymous$$d of transforms/quaternions you have direction Vector3's (not eulerAngle Vector3's), you could ins$$anonymous$$d find your rotation axis simply by using the cross product of the two direciton vectors.

avatar image drizztmainsword · Jun 07, 2012 at 10:37 PM 0
Share

I tried A and B with quaternions and the compiler yelled at me. So I looked the function up in the documentation and it says that Quaternion.FromToRotation(A, B) takes in Vector3's, not Quaternions.

avatar image Wolfram · Jun 07, 2012 at 10:43 PM 0
Share

Woops, my bad, sorry. Quaternion.FromToRotation() already requires directional vectors, so you can ignore that stuff about the cross product.

Well, what is your source where you want to derive A and B from, are these two Transforms? If so, and if the "direction" is determined by the +Z(=blue) axis, you coud use Quaternion.FromToRotation(source.transform.forward,target.transform.forward)

avatar image drizztmainsword · Jun 07, 2012 at 10:48 PM 0
Share

The points aren't in Transforms. They're Vector3s and Quaternions that I set with a custom inspector using their own set of handles.

The positions and rotations are all relative to the root of the character.

Show more comments
avatar image
0

Answer by bmod · Jan 06, 2018 at 08:25 PM

This works for me:

Quaternion.SlerpUnclamped(a, b, -t);

(Note the negative t value)

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

The best place to ask and answer questions about development with Unity.

To help users navigate the site we have posted a site navigation guide.

If you are a new user to Unity Answers, check out our FAQ for more information.

Make sure to check out our Knowledge Base for commonly asked Unity questions.

If you are a moderator, see our Moderator Guidelines page.

We are making improvements to UA, see the list of changes.



Follow this Question

Answers Answers and Comments

9 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

How to smoothly rotate to certain directions using input axis 1 Answer

Vector3.lerp giving me the incorrect Quaternion 1 Answer

Problem with First-Person-Control and Quaternion.Lerp 0 Answers

Quaternion.Lerp is not working ,causing weird rotations 0 Answers

Hot to Steer a Boat with Quaternion.Lerp? 0 Answers

  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges