Numa 32 Posted May 24, 2016 Report Share Posted May 24, 2016 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)); }; Quote Link to post Share on other sites

Numa 32 Posted May 24, 2016 Author Report Share Posted May 24, 2016 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? Quote Link to post Share on other sites

Deltakosh 4315 Posted May 24, 2016 Report Share Posted May 24, 2016 Lemme check Numa 1 Quote Link to post Share on other sites

Deltakosh 4315 Posted May 24, 2016 Report Share Posted May 24, 2016 I'm wondering if the "problem" could come from toQuaternion instead of the lerp Quote Link to post Share on other sites

Numa 32 Posted May 25, 2016 Author Report Share Posted May 25, 2016 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)); }; Quote Link to post Share on other sites

Numa 32 Posted May 25, 2016 Author Report Share Posted May 25, 2016 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(); } }; Quote Link to post Share on other sites

adam 755 Posted May 25, 2016 Report Share Posted May 25, 2016 http://www.babylonjs-playground.com/#2INAYY#3 I commented out the if (num4 > 0.999999) { in BABYLON.Quaternion. Quote Link to post Share on other sites

Deltakosh 4315 Posted May 25, 2016 Report Share Posted May 25, 2016 ok...sounds like a good update. Do you want submitting a PR with an additional parameter to lerp to enable "long version"? Quote Link to post Share on other sites

Numa 32 Posted May 25, 2016 Author Report Share Posted May 25, 2016 12 hours ago, adam said: http://www.babylonjs-playground.com/#2INAYY#3 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)); }; Quote Link to post Share on other sites

Deltakosh 4315 Posted May 26, 2016 Report Share Posted May 26, 2016 and did you tested if without long way enabled? Quote Link to post Share on other sites

Numa 32 Posted June 1, 2016 Author Report Share Posted June 1, 2016 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 Thanks for your help everyone Deltakosh 1 Quote Link to post Share on other sites

## Recommended Posts

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