Inverse Quaternion

hiker
Posts: 83
Joined: Tue Oct 24, 2006 11:52 pm
Location: Australia

Inverse Quaternion

Post by hiker »

Hi,

I need the heading (i.e. rotation around up axis) from a rotation, and since the euler functions restrict the returned heading to be between -90 and 90 degrees (I need between -180 and 180), I decided to try using quaternions directly (with which I am not too familiar).

I tried using a unit vector (facing in the original direction of the rigib body, i.e. (0,0,1)) and multiply it with the rotation quaternion as contained in the transform of the body, e.g.:

Code: Select all

btTransform trans;
m_body->getMotionState()->getWorldTransform(trans);
btQuaternion q =trans.getRotation();
btVector3 forward(0,0,1);
btVector3 direction = quatRotate(cur, forward);
and then use the projection of the resulting vector into the X-Z plane to determine the heading
(atan2(direction.getX(), direction,getZ()). I hope this approach makes sense :)

Unfortunately, quatRotate does not return what I expect it to return. If for example the rotation is the identity (q=(0,0,0,1)), I would expect that the result 'direction' is still (0,0,1). But in fact it is (0,0,-1). On the other hand, if I use the matrix instead (get the basis from the world transform, and multiply it with the forward vector), everything works as expected.

I think my problem can be summarised in the simple test case:

Code: Select all

  btQuaternion q;
  btMatrix3x3 m;
  m.setIdentity();
  m.getRotation(q);
  btVector3 v(0,0,1);
  btVector3 v2 = quatRotate(q,v);   // should be v pointing in the current direction
  btVector3 v3 = m*v;               // I expect this to be the same
  printf("q=(%f %f %f %f) * v=(%f %f %f) = %f %f %f\n",
         q.getX(), q.getY(), q.getZ(), q.getW(),
         v.getX(),v.getY(),v.getZ(),
         v2.getX(),v2.getY(),v2.getZ());
  printf("matrix*vector= %f %f %f\n",
         v3.getX(),v3.getY(),v3.getZ());
Running this program gives:

Code: Select all

q=(0.000000 0.000000 0.000000 1.000000) * v=(0.000000 0.000000 1.000000) = 0.000000 0.000000 -1.000000
matrix*vector= 0.000000 0.000000 1.000000
while I would expect the first line to result in (0,0,1) as well.

I can get the expected behaviour if I change bQuaternion::inverse() to return:
(-m_x, -m_y, -m_y, m_unusedW) instead of (m_x, m_y, m_z, -m_unusedW).
But not having too much an idea about quaternions, I am not sure what I am doing :)

Is my original idea simply wrong of using quaternions the way I did?

Besides, what is actually faster? After studying the bullet code I realised that btTransform is actually using a matrix (and not a quaternion as I suspected), so the quaternion is not the 'natural' data structure. And I guess that converting the matrix to a quaternion before the multiplication is actually more expensive than just multiplying the matrix by the vector.

Cheers,
Joerg
hiker
Posts: 83
Joined: Tue Oct 24, 2006 11:52 pm
Location: Australia

Re: Inverse Quaternion [fixed]

Post by hiker »

Just in case that somebody reads this: the problem was also discussed in the thread:
http://www.bulletphysics.com/Bullet/php ... 001&p=7894
and it has been fixed in bullet-2.68.

Thanks!
Joerg