Decompressing Quaternion Problem

Started by
12 comments, last by IggyPop 11 years, 9 months ago
Hi,

I'm a little bit stuck with decompressing my Quaternions used in key frame animation. Angles that are close to 180 are some times negative when they should not and vise versa.

Instead of -179.6 it should be 179.6 which causes a whole ~360 degree rotation when translating between say frame 5-10 since I drop certain frames.

My compression code:

[source lang="cpp"]
if(q.w < 0)
q.Flip(); // positive so i don't have to store sign

double scale = sqrt( q.v.x * q.v.x + q.v.y * q.v.y + q.v.z * q.v.z + q.w * q.w);

scale = (32767.0 / scale ) + 0.5;

floor(q.v.x * scale);
floor(q.v.y * scale);
floor(q.v.z * scale);
[/source]

Which gives me 3 signed __int16 values.

My Decompression code:
[source lang="cpp"]
static double scale = 32767.0 - 0.5;

q.v.x /= scale;
q.v.y /= scale;
q.v.z /= scale;

double temp = ( (q.v.x * q.v.x) + (q.v.y * q.v.y) + (q.v.z * q.v.z) );
if(temp > 1)
{
// wtf
}
q.w = sqrt(1 - temp);

[/source]

Also I sometimes get values of 'temp' that are > 1 which makes no sense (to me).

So if anyone can spot the error that would be great, I'm still learning smile.png



Results of my searching around before making a topic:

I came across a post on here that seamed relevant but I'm unsure as to what extra checks are required.
(Snip of post)


There are a couple of issues with this. First you need an additional sign bit to distinguish between w being posive and negative, both of which are possible. You can avoid this though by checking the sign of w before compressing and if it's negative multiply the whole quaternion by -1, so w is always positive and you take the positive square root when decompressing. But this can cause problems for some data - e.g. by introducing jumps into a sequence of keyframes of an animation, requiring extra checks when interpolating them.
[/quote]

Original Topic: http://www.gamedev.n...ed-quaternions/


I've also read: Game Programming Gems 3: Section 2.4 on quaternion compression be to no avial.


Thanks for your time.
Advertisement
You seem to be partially aware of the fact that q and -q both represent the same rotation. When you try to interpolate between two rotations, make sure the dot product of the two is positive, and flip one of them if it isn't.

Also, this seems wrong to me:
scale = (32767.0 / scale ) + 0.5;

floor(q.v.x * scale);
//...


You probably meant this:
scale = 32767.0 / scale;

floor(q.v.x * scale + 0.5); // Add 0.5 so effectively we round, instead of flooring (can be implemented as a `round' function)
//...

You seem to be partially aware of the fact that q and -q both represent the same rotation. When you try to interpolate between two rotations, make sure the dot product of the two is positive, and flip one of them if it isn't.


Yer I'm aware that both (-x, -y, -z, -w) and (x, y, z ,w) are the same angle.

And I flip it so I can take the postive square root.


When you try to interpolate between two rotations, make sure the dot product of the two is positive, and flip one of them if it isn't.


wait what your talking about when decompressing or compressing ?

My code works fine in terms of correct angle just when translating between 2 animation key frames it gets messed up.



Also, this seems wrong to me:
scale = (32767.0 / scale ) + 0.5;

floor(q.v.x * scale);
//...


You probably meant this:
scale = 32767.0 / scale;

floor(q.v.x * scale + 0.5); // Add 0.5 so effectively we round, instead of flooring (can be implemented as a `round' function)
//...



In my code I have the later I just made fails when removing my rnd() macro when posting topic, it makes no sense why i added 0.5 on the end of scale reading it myself lol.

[quote name='alvaro' timestamp='1341457549' post='4955831']
When you try to interpolate between two rotations, make sure the dot product of the two is positive, and flip one of them if it isn't.


wait what your talking about when decompressing or compressing ?[/quote]
Neither.

My code works fine in terms of correct angle just when translating between 2 animation key frames it gets messed up.[/quote]
This is what I am talking about. I don't know what "translating between 2 animation key frames" means, but one typically needs to fill in the frames between key frames, and does so by interpolating the data. When you interpolate between two rotations that are represented as quaternions, you need to do what I said: Check that the dot product of the two quaternions is positive, and flip one of them if it isn't.

In my code I have the later I just made fails when removing my rnd() macro when posting topic, it makes no sense why i added 0.5 on the end of scale reading it myself lol.
[/quote]
It's kind of annoying when people post edited code instead of what they are actually using, because very frequently they introduce new mistakes. I understand the need to simplify the code to show the problem more clearly, but you need to make sure the code you are posting still behaves the way you describe, so compile it and test it.

Particularly if you need help figuring out something like why sometimes the length is more than 1, post real code.

This is what I am talking about. I don't know what "translating between 2 animation key frames" means, but one typically needs to fill in the frames between key frames, and does so by interpolating the data. When you interpolate between two rotations that are represented as quaternions, you need to do what I said: Check that the dot product of the two quaternions is positive, and flip one of them if it isn't.


A thanks that might be the tip I needed.

I'll be more clear about what I'm doing interms of "translating between 2 animation key frames"

I'm reading the compressed quaternion and then converting it to Euler so that I can set a bones rotation via MEL in Maya.

For example sake I have rotation data for frames 1, 5, 10

some example data (made up):

Frame 1: -90, 0 , 179.2
Frame 5: -85, 2, - 179.8
Frame 10: -88, 3, 178.4


When the animation is played the bone rotates allmost 360 between the two keyframes when there should only be 2-3 degrees of rotation.





It's kind of annoying when people post edited code instead of what they are actually using, because very frequently they introduce new mistakes. I understand the need to simplify the code to show the problem more clearly, but you need to make sure the code you are posting still behaves the way you describe, so compile it and test it.

Particularly if you need help figuring out something like why sometimes the length is more than 1, post real code.


no problem I won't post edited code again, also was not a good idear to edit it after been awake for 26hrs lmao.

I'll be more clear about what I'm doing interms of "translating between 2 animation key frames"

I'm reading the compressed quaternion and then converting it to Euler so that I can set a bones rotation via MEL in Maya.

[...]

When the animation is played the bone rotates allmost 360 between the two keyframes when there should only be 2-3 degrees of rotation.


Well, Euler angles are a notoriously bad representation to interpolate, so you shouldn't do that regardless. Interpolate the quaternions (look up slerp and nlerp), then convert to Euler angles if you really have to because of the particularities of some API.

[quote name='IggyPop' timestamp='1341501640' post='4956005']
I'll be more clear about what I'm doing interms of "translating between 2 animation key frames"

I'm reading the compressed quaternion and then converting it to Euler so that I can set a bones rotation via MEL in Maya.

[...]

When the animation is played the bone rotates allmost 360 between the two keyframes when there should only be 2-3 degrees of rotation.


Well, Euler angles are a notoriously bad representation to interpolate, so you shouldn't do that regardless. Interpolate the quaternions (look up slerp and nlerp), then convert to Euler angles if you really have to because of the particularities of some API.
[/quote]

Would that not require the quaternions to be correct ?

Since if I slerp it's just going to give me values between frame 1 - 5 which is not what I need but frames 5 angles to be correct.
I don't think you understand what the problem is. Or perhaps I don't. It's not that the angles at frame 5 are incorrect, but it's that interpolating angles doesn't do what you want. So interpolate quaternions instead, which behaves much much better.

I don't think you understand what the problem is. Or perhaps I don't. It's not that the angles at frame 5 are incorrect, but it's that interpolating angles doesn't do what you want. So interpolate quaternions instead, which behaves much much better.


Ok I explain again just to make sure, thanks for you help so far.


Some frames have angles that are negative for example -179.9 when THEY should be 179.9 in order for the animation to be correct.

So when I key frame 1 as 179.9 and frame 5 as -179.9(the incorrect angle) maya translates between frames rotating 360 degrees (to get from -179 to 179) instead of there been very little rotation if the correct angles are used.


-179.9 is the same as 180.1 which would only cause 0.2 degress of rotation between frames like it should be.
Is there a reason the anlge is negative when it shouldn't be, maybe it's todo with been so close to 180.
-179.9 and 180.1 are the same angle. So the angle isn't "incorrect" in any meaningful way. If the point is that it should be 179.9 and not 180.1, you need to make your code more robust.

Again, if you use quaternions during the interpolation, many problems will go away.

This topic is closed to new replies.

Advertisement