# Lerping quaternions the long way

## Recommended Posts

Hi there,

by default it seems the ANIMATIONTYPE_QUATERNION slerps between 2 quaternions the short way (270 degrees turns into -90 for instance).

If I compute the angle between the 2 quaterinon and determine that it's more than 180, how would I go about slerping it the long way?

I tried looking at the code but variable names such as num1 num2 num3 num4 num5 num6 didn't really help  Any help appreciated!

Cheers,

``````Quaternion.Slerp = function (left, right, amount) {
var num2;
var num3;
var num = amount;
var num4 = (((left.x * right.x) + (left.y * right.y)) + (left.z * right.z)) + (left.w * right.w);
var flag = false;
if (num4 < 0) {
flag = true;
num4 = -num4;
}
if (num4 > 0.999999) {
num3 = 1 - num;
num2 = flag ? -num : num;
}
else {
var num5 = Math.acos(num4);
var num6 = (1.0 / Math.sin(num5));
num3 = (Math.sin((1.0 - num) * num5)) * num6;
num2 = flag ? ((-Math.sin(num * num5)) * num6) : ((Math.sin(num * num5)) * num6);
}
return new Quaternion((num3 * left.x) + (num2 * right.x), (num3 * left.y) + (num2 * right.y), (num3 * left.z) + (num2 * right.z), (num3 * left.w) + (num2 * right.w));
};``````

##### Share on other sites

Here is a playground: http://www.babylonjs-playground.com/#2INAYY#2 but as we all know it rotates the short way.

On line 29/30 could I split the rotation into 2 chained animations maybe?

Lemme check

##### Share on other sites

I'm wondering if the "problem" could come from toQuaternion instead of the lerp

##### Share on other sites

The slerp function explicitly flips things when the angle is greater than 180 (when num4 < 0). I tried to take all that out but it caused some objects in my scene to be moved infinitely in a direction:

``````Quaternion.Slerp = function (left, right, amount) {
var num2;
var num3;
var num = amount;
var num4 = (((left.x * right.x) + (left.y * right.y)) + (left.z * right.z)) + (left.w * right.w);
/*var flag = false;*/
if (num4 < 0) {
//flag = true;
//num4 = -num4;
}
if (num4 > 0.999999) {
num3 = 1 - num;
num2 = /*flag ? -num :*/ num;
}
else {
var num5 = Math.acos(num4);
var num6 = (1.0 / Math.sin(num5));
num3 = (Math.sin((1.0 - num) * num5)) * num6;
num2 = /*flag ? ((-Math.sin(num * num5)) * num6) : */((Math.sin(num * num5)) * num6);
}
return new Quaternion((num3 * left.x) + (num2 * right.x), (num3 * left.y) + (num2 * right.y), (num3 * left.z) + (num2 * right.z), (num3 * left.w) + (num2 * right.w));
};``````

##### Share on other sites

I also tried to reproduce the Slerp alogithm from the Ogre engine, I'm pretty sure I got it right but it still doesn't rotate properly / makes objects disappear until the last frame is reached:

``````Quaternion.Slerp = function (left, right, amount) {

var shortestPath = false;

var dotProduct = (left.x * right.x) + (left.y * right.y) + (left.z * right.z) + (left.w * right.w);

if (dotProduct < 0.0 && shortestPath)
{
dotProduct = -dotProduct;
right = right.scale(-1);
}

if (Math.abs(dotProduct < 0.99999))
{
var sin = Math.sqrt(1 - Math.sqrt(dotProduct));
var angle = Math.atan2(sin, dotProduct);
var inverseSin = 1.0 / sin;
var coeff0 = Math.sin((1.0 - amount) * angle) * inverseSin;
var coeff1 = Math.sin(amount * angle) * inverseSin;

return new Quaternion((coeff0 * left.x) + (coeff1 * right.x), (coeff0 * left.y) + (coeff1 * right.y), (coeff0 * left.z) + (coeff1 * right.z), (coeff0 * left.w) + (coeff1 * right.w));
}
else
{
var coeff0 = (1.0 - amount);
var coeff1 = amount;

var t = new Quaternion((coeff0 * left.x) + (coeff1 * right.x), (coeff0 * left.y) + (coeff1 * right.y), (coeff0 * left.z) + (coeff1 * right.z), (coeff0 * left.w) + (coeff1 * right.w));
return t.normalize();
}
};``````

##### Share on other sites

I commented out the

if (num4 > 0.999999) {

in BABYLON.Quaternion.

##### Share on other sites

ok...sounds like a good update.

Do you want submitting a PR with an additional parameter to lerp to enable "long version"?

##### Share on other sites

I commented out the

if (num4 > 0.999999) {

in BABYLON.Quaternion.

Oh yeah it actually works in the playground!

It still doesn't work on my project though, everything disappears during the animation and I only get the last frame. Any idea why? I tried plugging in my values in the playground and they work fine but for some reason it breaks my animation, and there's nothing in the logs.

----------------------
That IF actually needs to be there (it still works if you leave it as long as you remove the flag part).

If the dot product of 2 quaternions nears -1, they are nearly parallel and the spherical interpolation isn't numerically stable so we must do a linear interpolation there.

If the dot product nears 1, they are almost identical and there is no need for a spherical interpolation either so again we do a linear one.

that IF normally checks for the dot product's absolute value since we flip num4 if it's negative. If you get rid of that first IF then you need to use Math.abs otherwise we're missing the case where the dot product nears -1. So the long-way version should look like this:

``````BABYLON.Quaternion.Slerp = function (left, right, amount) {
var num2;
var num3;
var num = amount;
var num4 = (((left.x * right.x) + (left.y * right.y)) + (left.z * right.z)) + (left.w * right.w);
if (Math.abs(num4) > 0.999999) {

// DO LINEAR INTERPOLATION
num3 = 1 - num;
num2 = num;
// which later translates to: (1.0 - amount) * left + amount * right;
}
else {
var num5 = Math.acos(num4);
var num6 = (1.0 / Math.sin(num5));
num3 = (Math.sin((1.0 - num) * num5)) * num6;
num2 = (Math.sin(num * num5)) * num6);
}
return new BABYLON.Quaternion((num3 * left.x) + (num2 * right.x), (num3 * left.y) + (num2 * right.y), (num3 * left.z) + (num2 * right.z), (num3 * left.w) + (num2 * right.w));
};``````

##### Share on other sites

and did you tested if without long way enabled?

##### Share on other sites

Hi, sorry I've been away for a while. It turns out those fixes worked fine, my graphics card seems to be the issue, it's a bit old and for some reason was giving up on the animation all together. I tried it on a different computer and it played fine both ways

## Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

×   Pasted as rich text.   Paste as plain text instead

Only 75 emoji are allowed.

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.