Started by Mar 27 2012 04:17 AM

,
11 replies to this topic

Posted 27 March 2012 - 04:17 AM

Hey guys,

I am trying to do the object manipulation of the character in the game that I'm currently working on. So, the object should always face the character while it is being carried. In order to this, I can easily set the rotation of the object to the rotation of the character. But Havok physics don't work this way, and whenever there is collision, physics would freak out.

In order for physics to work smoothly, I would get the current rotation of the object which is in quaternions. Then I would know my desired rotation in quaternion based on the rotation of the camera, and then I would apply angular impulse to the object in a way that it goes from current quaternion to desired quaternion.

The problem here is that ApplyAngularImpulse in havok gets euler angles as argument. So, what I did was that I converted the current and desired quaternions to Euler Angles, and then I substracted them, and applied the agular impulse to the object. (Of course I damped it so that it would stop in the desired rotation). However, this method only works for half of the space. Because when you convert from quaternions to euler angles, for half of the space it changes continiously, but for the other half, there are gaps between different parts of the space. So the object would rotate smoothly on the one half, but on the other, it wouldn't know which way to rotate because of those gaps.

I also have tried getting the quaternion that goes from current quaternion to the desired one, and then converting it to euler, and applying angular impulse based on that, but that also has a similar kind of problem.

I am really stuck here, and don't know what to do at this point. If anyone can point me in the right direction, I would really appreciate it.

Thank you.

I am trying to do the object manipulation of the character in the game that I'm currently working on. So, the object should always face the character while it is being carried. In order to this, I can easily set the rotation of the object to the rotation of the character. But Havok physics don't work this way, and whenever there is collision, physics would freak out.

In order for physics to work smoothly, I would get the current rotation of the object which is in quaternions. Then I would know my desired rotation in quaternion based on the rotation of the camera, and then I would apply angular impulse to the object in a way that it goes from current quaternion to desired quaternion.

The problem here is that ApplyAngularImpulse in havok gets euler angles as argument. So, what I did was that I converted the current and desired quaternions to Euler Angles, and then I substracted them, and applied the agular impulse to the object. (Of course I damped it so that it would stop in the desired rotation). However, this method only works for half of the space. Because when you convert from quaternions to euler angles, for half of the space it changes continiously, but for the other half, there are gaps between different parts of the space. So the object would rotate smoothly on the one half, but on the other, it wouldn't know which way to rotate because of those gaps.

I also have tried getting the quaternion that goes from current quaternion to the desired one, and then converting it to euler, and applying angular impulse based on that, but that also has a similar kind of problem.

I am really stuck here, and don't know what to do at this point. If anyone can point me in the right direction, I would really appreciate it.

Thank you.

Posted 27 March 2012 - 05:04 AM

I don't fully understand your problem, but your description suggests a possible solution: Instead of converting both quaternions to Euler angles and then subtracting, try dividing the quaternions and then converting the result to Euler angles. [EDIT: Although a later sentence seems to indicate you have already tried that...]

Posted 28 March 2012 - 03:48 AM

Thank you for your answer alvaro. But yeah, I have tried that too. So, here is what happens to the desired rotation after I convert to Euler angles:

For the half of space that it works:

y goes from -PI/2 to PI/2

x goes from (-PI/2 + alpha) (Looking Down) to (PI/2 - alpha) (Looking up)

Note that alpha exists because the degree of freedom for the camera is limited as we look all the way downwards or upwards.

z is zero

For the half of space that it doesn't work:

y goes from -PI/2 to PI/2

x goes from (PI/2 + alpha) to PI (This is for looking all the way down to looking straight) and from -PI to (-PI/2 - alpha) (This is for looking straight to looking all the way up)

Notice the gap between PI and -PI when looking straight

z has the same kind of behavior as x, only that it is even worse and it has much more gaps. It is either -PI or PI.

So, now you can see what goes bad when it wants to go from current to desired. Because of the gaps and these inconsistencies, it wouldn't know which direction to go, and then it would freak out.

When I say it has a similar problem when converting the quaternion that goes from current to desired into Euler angles, it is because of the fact that these gaps still exist in the converted quaternion.

Thank you for your time, I would really appreciate any help.

For the half of space that it works:

y goes from -PI/2 to PI/2

x goes from (-PI/2 + alpha) (Looking Down) to (PI/2 - alpha) (Looking up)

Note that alpha exists because the degree of freedom for the camera is limited as we look all the way downwards or upwards.

z is zero

For the half of space that it doesn't work:

y goes from -PI/2 to PI/2

x goes from (PI/2 + alpha) to PI (This is for looking all the way down to looking straight) and from -PI to (-PI/2 - alpha) (This is for looking straight to looking all the way up)

Notice the gap between PI and -PI when looking straight

z has the same kind of behavior as x, only that it is even worse and it has much more gaps. It is either -PI or PI.

So, now you can see what goes bad when it wants to go from current to desired. Because of the gaps and these inconsistencies, it wouldn't know which direction to go, and then it would freak out.

When I say it has a similar problem when converting the quaternion that goes from current to desired into Euler angles, it is because of the fact that these gaps still exist in the converted quaternion.

Thank you for your time, I would really appreciate any help.

Posted 28 March 2012 - 07:22 AM

Several things:

- If you could isolate one instance where your computations do the wrong thing and post it, it would be much easier to help you.
- I don't think ApplyAngularImpulse gets Euler angles as input: An angular impulse is a three-dimensional vector and that's what the function takes.
- I have another idea as to what might be wrong: Are you aware that the same attitude can be represented with two quaternions, q and -q? Perhaps you need to flip the sign of one of them (target and current) to avoid a whole flip?

Posted 29 March 2012 - 06:27 PM

Thanks so much for the answer.

**For the Good Side(the side that works):**

**When looking all the way up:**

**desired quaternion:****converted desired euler:**

**When looking all the way down:**

**desired quaternion:****converted desired euler:**

**On the BAD Side:**

**When looking all the way up:**

**desired quaternion:****desired euler:**

**When looking all the way down:**

**desired quaternion:****converted desired euler: **

However on the bad side, when I move my cursor from all the way up to all the way down, x goes from -1.74 to -3.14(when looking straight). Then it goes from 3.14 to 1.74. So you see that gap of 2*PI when looking straight. z is even worst. When going from all the way up to all the way down, z is constantly jumping(it's either 3.14 or -3.14).

I hope this gives you a better understanding of what is going wrong right now. Because of these gaps that I have on the bad side, current euler cannot go to desired euler which makes the object to freak out. It is constantly changing the direction in which to rotate.

I would really appreciate it if anyone has a solution for this problem. Thank you.

- For ApplyAngularImpulse you are absolutely right, it takes a three dimensional vector. But those three values would have the same effect of roll, pitch, and yaw in the Euler angles, please correct me if I'm wrong about this.
- About flipping the quaternions, I tried that too. But, the problem doesn't come from there. Let me give you an example of when the computations go wrong:

- x: 0.623505
- y: 0.18474
- z: -0.154878
- w: 0.743724167

- x: 1.39539
- y: 0.486941
- z: 0

- x: -0.602746
- y: 0.265235
- z: 0.222362
- w: 0.718959987

- x: -1.39539
- y: 0.70685
- z: 0

- x: 0.176007
- y: 0.737006
- z: -0.617873
- w: 0.209943473

- x: -1.7462
- y: 0.555019
- z: 3.14159

- x: -0.154882
- y: 0.743722
- z: 0.623505
- w: 0.184744284

- x: 1.7462
- y: 0.486954
- z: -3.14159

However on the bad side, when I move my cursor from all the way up to all the way down, x goes from -1.74 to -3.14(when looking straight). Then it goes from 3.14 to 1.74. So you see that gap of 2*PI when looking straight. z is even worst. When going from all the way up to all the way down, z is constantly jumping(it's either 3.14 or -3.14).

I hope this gives you a better understanding of what is going wrong right now. Because of these gaps that I have on the bad side, current euler cannot go to desired euler which makes the object to freak out. It is constantly changing the direction in which to rotate.

I would really appreciate it if anyone has a solution for this problem. Thank you.

Posted 29 March 2012 - 06:41 PM

Also, this is how I calculate my euler based on the given quaternion q.

float q0 = q->getReal(); //w float q1 = q->getImag().getComponent(0); //x float q2 = q->getImag().getComponent(1); //y float q3 = q->getImag().getComponent(2); //z float euler_x = atan2(2.0*(q0*q1+q2*q3),1.0-2.0*(q1*q1 + q2*q2)); float euler_y = asin(2.0*(q0*q2-q3*q1)); float euler_z = atan2(2.0*(q0*q3+q1*q2),1.0-2.0*(q2*q2+q3*q3));

Posted 29 March 2012 - 09:39 PM

So you are converting the quaternions to Euler angles and then you are interpolating between them? That won't work: You interpolate between the quaternions, using either slerp or nlerp. Is that the problem? I don't see why you ever need to convert to Euler angles.

Posted 30 March 2012 - 12:44 PM

No, I am not interpolating. I am not trying to get any values between my two quaternions. After I convert my current and desired quaternion to euler angles, I then do:

angular_impulse = desired_euler - current_euler;

applyAngularImpulse(angular_impulse);

If you think I do not have to convert to euler to apply this impulse, then how do you think I can get my angular_impulse based on my current_quaternion and desired_quaternion?

Thank you.

angular_impulse = desired_euler - current_euler;

applyAngularImpulse(angular_impulse);

If you think I do not have to convert to euler to apply this impulse, then how do you think I can get my angular_impulse based on my current_quaternion and desired_quaternion?

Thank you.

Posted 30 March 2012 - 02:32 PM

You cannot subtract two euler angle triplets from each other to get a difference. That is, the expression "angular_impulse = desired_euler - current_euler;" is wrong math.

If your physics function wants the angular impulse input as an euler, first compute the difference as a quaternion (desired_quaternion * current_quaternion^-1), then convert that quaternion to euler and feed it to applyAngularImpulse.

If your physics function wants the angular impulse input as an euler, first compute the difference as a quaternion (desired_quaternion * current_quaternion^-1), then convert that quaternion to euler and feed it to applyAngularImpulse.

Me+PC=clb.demon.fi | C++ Math and Geometry library: MathGeoLib, test it live! | C++ Game Networking: kNet | 2D Bin Packing: RectangleBinPack | Use gcc/clang/emcc from VS: vs-tool | Resume+Portfolio | gfxapi, test it live!

Posted 30 March 2012 - 05:19 PM

clb is right about the difference of Euler angles not making sense, and about how (desired_quaternion * conj(current_quaternion)) being the right thing to compute (the conjugate and the inverse are the same because we are dealing with unit quaternions). However, I don't think you need to convert to Euler angles at the end. You may want to compute the log of the result instead, or something like that. But I don't fully understand what you are doing, because the impulse is not something you can use to move from one position to another, but something that you can use to change from one velocity to another. Similarly, an angular impulse can be used to change from one angular velocity to another, not to go from one attitude to another. So I don't really understand what you are doing.

Posted 01 April 2012 - 06:08 AM

Thank you guys for the answers.

First, I do not agree that the expression "angular_impulse = desired_euler - current_euler;" is wrong math. Because it seems to be working for half of the space. But since you are both emphasizing on this matter, I'm gonna drop it and focus on the quaternion: rotation_amount = desired_quaternion * current_quaternion^-1.

I made a youtube video of what is going wrong. Hopefully this would give you guys a better understanding of where the problem might come from. Here, I'm applying angular_impulse by just converting the quaternion that goes from current to desired to euler angles.

http://www.youtube.com/watch?v=QwnWyWDx6OI

Also alvar, doing something on the quaternion itself might help, and it sounds interesting. I have also tried to do some stuff with it, but haven't got anything out of it. I haven't tried the log thing you mentioned yet. Would you please tell me how to get x,y,z for the impulse based on the rotation_amount quaternion and doing log?

Moreover, impulse or force/torque CAN be used to move from one position/rotation to the other. applyLinearForce is what I am using to change the position of the object while holding it. It is the same technique with current position and desired position, and applying linear impulse based on desired-current to get to the desired position. You can see in the video above that it works very smoothly for the position of the object. It's also working for the rotation but unfortunately only for half of the space.

Thanks again, and I appreciate your help

First, I do not agree that the expression "angular_impulse = desired_euler - current_euler;" is wrong math. Because it seems to be working for half of the space. But since you are both emphasizing on this matter, I'm gonna drop it and focus on the quaternion: rotation_amount = desired_quaternion * current_quaternion^-1.

I made a youtube video of what is going wrong. Hopefully this would give you guys a better understanding of where the problem might come from. Here, I'm applying angular_impulse by just converting the quaternion that goes from current to desired to euler angles.

http://www.youtube.com/watch?v=QwnWyWDx6OI

Also alvar, doing something on the quaternion itself might help, and it sounds interesting. I have also tried to do some stuff with it, but haven't got anything out of it. I haven't tried the log thing you mentioned yet. Would you please tell me how to get x,y,z for the impulse based on the rotation_amount quaternion and doing log?

Moreover, impulse or force/torque CAN be used to move from one position/rotation to the other. applyLinearForce is what I am using to change the position of the object while holding it. It is the same technique with current position and desired position, and applying linear impulse based on desired-current to get to the desired position. You can see in the video above that it works very smoothly for the position of the object. It's also working for the rotation but unfortunately only for half of the space.

Thanks again, and I appreciate your help

Posted 01 April 2012 - 08:02 AM

The impulse is not in euler angles but a Vector3 that describes the **rotational axis**.

You can get the quaternion that will rotate from q1 to q2 by:

q' = q1^{-1}q2

then convert q' to angle-axis and put it in ApplyAngularImpulse.

Basically, Euler angles are just a more human readable form of rotation and you should never have to use them directly in your code.

You can get the quaternion that will rotate from q1 to q2 by:

q' = q1

then convert q' to angle-axis and put it in ApplyAngularImpulse.

Basically, Euler angles are just a more human readable form of rotation and you should never have to use them directly in your code.