Lerping a rotation

Recommended Posts

rgibson11    130
I have a small problem.
My multiplayer game currently has a packet being delivered every 100ms.
The packet contains position and a heading angle which is -pi to pi.

I am actually rendering 100ms behind real server time in order to be able to lerp the positions (which work fine). I tried to lerp the heading angle this way and it works but theres a sudden snapback at the end of every rotation. I just cant figure out what it could be

//lerp:
//return a + (b - a) * t;

float h1 = (*ito).headings.front(); //Heading 100ms agofloat h2 = (*ito).headings.back(); //Current server headingfloat currh = 0.0f; //Lerped headingcurrh = Math::lerp(h1, h2, zlerp);//zlerp = elapsed time since last update / 100.0 (ms) This works perfect for pos

Anyone could know what im doing wrong?

Share on other sites
snake5    1587
You can't lerp between angles without problems. You can either use SLERP or normalize the angles, find the fastest route from one angle to another (remember - angle is equal to the remainder of a division between that angle and the "full circle angle" in the same units, 2 pi radians or 360 degrees), modify the 2nd angle to make it fit the fastest route and only then do a lerp between those angles.

http://en.wikipedia.org/wiki/Modulo_operation

Share on other sites
skytiger    294
I calculate the shortest difference between two angles like this:

d = b - a;a = abs(d);s = sign(d);if (a > pi) { d = s * (2 * pi - a) * -1;}//if

now you can:

lerp = a + d * i;

you can map back into (-pi,pi) range using the same code again:

a = abs(d);s = sign(d);if (a > pi) { d = s * (2 * pi - a) * -1;}//if

this uses less cycles than modulo

Share on other sites
rgibson11    130
That seems to help but my maths isnt that great?
Do you have a quick example of what you said? or should I go ahead learning slerp.
Also why is your user rating so low? :S

-edit thanks skytiger. I got an example now. cheers :D

Share on other sites
bubu LV    1436
Quote:
 Original post by snake5You can either use SLERP or normalize the angles

Isn't slerp only for 3d rotation, not 1d angle?

Share on other sites
Emergent    982
Quote:
Original post by bubu LV
Quote:
 Original post by snake5You can either use SLERP or normalize the angles

Isn't slerp only for 3d rotation, not 1d angle?

SLERP gets you between points on a sphere.

What do points on a sphere have to do with rotations?

In 3d, you can represent a rotation as a unit quaternion; the unit quaternions lie on a sphere in four dimensions, so you can use SLERP to get between them.

In 2d, you can represent a rotation as a unit vector. The unit vectors lie on a sphere in 2 dimensions (i.e., a circle), so you can use SLERP to get between them.

In both cases, this does what you want because the notion of distance on the sphere agrees with what you'd want to call the distance between two rotations.

Share on other sites
rgibson11    130
Quote:
 Original post by skytigerI calculate the shortest difference between two angles like this:*** Source Snippet Removed ***now you can:*** Source Snippet Removed ***you can map back into (-pi,pi) range using the same code again:*** Source Snippet Removed ***this uses less cycles than modulo

What is sign() ? Is that a function you made yourself? cant find it anywhere in standard libraries

Share on other sites
rubicondev    296
try sgn()

Share on other sites
rgibson11    130
Ok I tried using slerp and it seems to be working very well.
Except for one slight error.
The rotations are smooth as hell except sometimes it stops rotation and quickly rotates the other way.

Please can someone who is familiar with slerps check this code. I would be very greatful. Im sure its some simple error im making

float h1 = (*ito).headings.front(); //100ms behind server timefloat h2 = (*ito).headings.back(); //Current server timefloat hcurr = 0.0f;Quaternion hh1, hh2, ff;float uu, uu2, uu3;hh1.fromHeadPitchRoll(h1, 0.0f, 0.0f);hh2.fromHeadPitchRoll(h2, 0.0f, 0.0f);ff = Quaternion::slerp(hh1, hh2, zlerp); //zlerp = time since last update / 100.0ff.toHeadPitchRoll(uu, uu2, uu3); //uu should be the slerped heading angle

the actual slerp function is from a well known maths library so im pretty sure its correct

Share on other sites
jyk    2094
Quote:
 Original post by rgibson11the actual slerp function is from a well known maths library so im pretty sure its correct
What math library is it? Does the SLERP function in question correct for quaternion aliasing?

Share on other sites
RobTheBloke    2553
Quote:
 I tried to lerp the heading angle this way and it works but theres a sudden snapback at the end of every rotation. I just cant figure out what it could be

The shortest path between -179 degrees and 179 degrees is 2 degrees. Lerp functions see that as 358 degrees.... That's usually the problem.

Quote:
 Original post by rgibson11The rotations are smooth as hell except sometimes it stops rotation and quickly rotates the other way.

It sounds as though the slerp function you are using is not performing a dot product to (potentially) flip the second quat? Does this fix it?

float h1 = (*ito).headings.front(); //100ms behind server timefloat h2 = (*ito).headings.back(); //Current server timefloat hcurr = 0.0f;Quaternion hh1, hh2, ff;float uu, uu2, uu3;hh1.fromHeadPitchRoll(h1, 0.0f, 0.0f);hh2.fromHeadPitchRoll(h2, 0.0f, 0.0f);if(Quaternion::dot(hh1, hh2) < 0){  hh2.x = -hh2.x;  hh2.y = -hh2.y;  hh2.z = -hh2.z;  hh2.w = -hh2.w;}ff = Quaternion::slerp(hh1, hh2, zlerp); //zlerp = time since last update / 100.0ff.toHeadPitchRoll(uu, uu2, uu3); //uu should be the slerped heading angle

Share on other sites
rgibson11    130
Quote:
Original post by RobTheBloke
Quote:
 I tried to lerp the heading angle this way and it works but theres a sudden snapback at the end of every rotation. I just cant figure out what it could be

The shortest path between -179 degrees and 179 degrees is 2 degrees. Lerp functions see that as 358 degrees.... That's usually the problem.

Quote:
 Original post by rgibson11The rotations are smooth as hell except sometimes it stops rotation and quickly rotates the other way.

It sounds as though the slerp function you are using is not performing a dot product to (potentially) flip the second quat? Does this fix it?

*** Source Snippet Removed ***

You are absolutely amazing, works perfectly now. Thanks so much. ++Rating;