Quaternion multiplication

Get answers to all your basic programming questions. No Ogre questions, please!
drwbns
Orc Shaman
Posts: 788
Joined: Mon Jan 18, 2010 6:06 pm
Location: Costa Mesa, California
x 24

Quaternion multiplication

Post by drwbns »

I've been reading the quaternion primer and found it pretty interesting that multiplication of quaternions is non-commutative. But how does a multiplication result of 2 or more quaternions store the order of those rotations? Also, when multiplying a quat by a vector3, the primer says we get a vector describing the rotational offset from that vector. But, it says further that getting an orientation quat, multiplied by Vector3::UNIT_X, gets us the direction vector. This seems to be saying 2 different things. Is it a rotational offset, or a direction vector? How can it be both?
User avatar
Jabberwocky
OGRE Moderator
OGRE Moderator
Posts: 2819
Joined: Mon Mar 05, 2007 11:17 pm
Location: Canada
x 218

Re: Quaternion multiplication

Post by Jabberwocky »

The best way to think of a quaternion is that it is a rotation.

For example, you could have a quaternion that means "turn 90 degrees left". Or maybe more accurately (for 3D), "turn 90 degrees clockwise around the +Y axis". But it's a little easier to describe the concepts using "left", "right", "north", "south", etc.

By itself, a quaternion can't tell you an absolute orientation. If I told you I turned 90 degrees left, then asked "what direction am I facing?", you would say "it depends on what direction you were facing when you started". If I started out facing north, then I would now be facing west. If I started out by facing south, then I would now be facing east.

But a quaternion often is used to represent an absolute orienation. This is why in Ogre, SceneNodes (and other "Node" classes) store their orientation as a Quaternion. Here's how that works.

When you're making models for your game, your artist should always design them to have the same orientation. In Ogre, the most common convention is: -z is forward, +y is up. So now, since you know exactly how your model is facing by default, you can use a quaternion to rotate it, and get a new orientation.

Using the simplified north/south/east/west/left/right description, it would go like this.
We make all our models so that they're facing north.
Now, if we want a model to face west, we give it a "turn left 90 degrees" quaternion, which results in an orientation of facing west.
If we want a model to face south-east, we give it a "turn right 135 degrees" quaternion, which results in an orientation of facing SE.
Again, this only makes sense if we know the default orientation (northwards).
drwbns wrote:But how does a multiplication result of 2 or more quaternions store the order of those rotations?
It doesn't. It just remembers the result.
If I'm facing SouthEast, I could have gotten here by:
1) Turning 180 degrees right, then turning 45 degrees left
or
2) Turning 100 degrees right, then turning 35 degrees right
or
3) Turning 20 degrees left, then turning 155 degrees right
or...
All of these would result in the same final quaternion, which tells you which way I'm facing, but not how I got here.
drwbns wrote:Also, when multiplying a quat by a vector3, the primer says we get a vector describing the rotational offset from that vector. But, it says further that getting an orientation quat, multiplied by Vector3::UNIT_X, gets us the direction vector. This seems to be saying 2 different things. Is it a rotational offset, or a direction vector? How can it be both?
It's a direction vector.
Although since ogre commonly use Vector3:NEGATIVE_UNIT_Z as the default direction of our models, usually if you want the direction of an Entity, you multiply the Entity's quaternion/orientation by Vector3:NEGATIVE_UNIT_Z to get it's direction vector.

If I wanted to make a space ship fire a bullet, the (simplified) code would look something like this:

Code: Select all

void FireBulletFromShip( Ogre::Entity* pShip )
{
   // All position and orientation info is stored on the SceneNode
   // - this code assumes our SceneNode is attached directly to ogre's root SceneNode.
   // - if it's not, use the _getDerivedPosition and _getDerivedOrientation functions instead
   Ogre::SceneNode* pSN = pShip->getSceneNode();   
   Ogre::Vector3 shipPosition = pSN->getPosition();
   Ogre::Quaternion shipOrientation = pSN->getOrientation();

   // Our models are built with a default forward direction of NEGATIVE_UNIT_Z
   Ogre::Vector3 forwardDefault = Ogre::Vector3::NEGATIVE_UNIT_Z;

   // What is the ship's current direction?
   Ogre::Vector3 currentDirection = shipOrientation * forwardDefault;   

   // Fire the bullet in the ship's current direction
   // Let's pretend the following function can make a bullet, but just has to be told what position and direction to fire it
   CreateBullet( shipPosition, currentDirection );
}
Image
drwbns
Orc Shaman
Posts: 788
Joined: Mon Jan 18, 2010 6:06 pm
Location: Costa Mesa, California
x 24

Re: Quaternion multiplication

Post by drwbns »

Thanks for that info. How would I make a player control style where movement is based upon the camera angle to the player?
User avatar
Jabberwocky
OGRE Moderator
OGRE Moderator
Posts: 2819
Joined: Mon Mar 05, 2007 11:17 pm
Location: Canada
x 218

Re: Quaternion multiplication

Post by Jabberwocky »

That's a fairly complicated question. But it would involve getting the direction the camera is pointing, and gradually (or immediately) rotating the character to face that direction. Check the "character" sample program which comes with Ogre3D. Maybe that's close to what you're looking for?
Image
drwbns
Orc Shaman
Posts: 788
Joined: Mon Jan 18, 2010 6:06 pm
Location: Costa Mesa, California
x 24

Re: Quaternion multiplication

Post by drwbns »

Yeah, that's what I'm working with but somehow my rotations are off. Pressing left makes him walk away from the camera, up makes him move right from the camera, right makes him move towards the camera, and down makes him move left from the camera. The only thing I'm not using is the cameraNode, as I'm passing the camera's orientation in place of the cameraNode, and I'm using Havok for physics.

If I remove my physics update, and leave the original code as is, minus using the cameraNode ( mCamera instead ) and minus the translate call, the character doesn't even turn. Only just very slightly can I see some hint of turning left and right, maybe a degree if that. Like there's a lock on turning somehow.

I noticed that my Sinbad character is actually facing +Z when loaded, is this a rotation problem with the Sinbad character? I'm not rotating the node...
User avatar
Jabberwocky
OGRE Moderator
OGRE Moderator
Posts: 2819
Joined: Mon Mar 05, 2007 11:17 pm
Location: Canada
x 218

Re: Quaternion multiplication

Post by Jabberwocky »

Here's some code I wrote.
It's completely untested and uncompiled, but hopefully if I didn't screw up too bad, it might help.

Code: Select all

   Quaternion cameraOrientation = pCamera->getDerivedOrientation();
   
   // You could get the camera's direction like this:
   Vector3 cameraDirection = cameraOrientation * Vector3::NEGATIVE_UNIT_Z;

   // Alternatively, you can use this function:  Camera::getDerivedDirection
   // but if you look at the source code for that (OgreCamera.cpp), it's doing the exact same thing as the code above.

   // If your character is standing on the ground, you probably want to ignore the y ("up/down") component of your camera direction,
   // since the character can't walk into the air or into the ground.
   cameraDirection.y = 0.f;

   // TODO:  check if cameraDirection is now 0, which would now be the case if the cameraDirection was pointing straight up (UNIT_Y) or straight down (NEGATIVE_UNIT_Y)
   // If so, return now since we can't move the player relative to the camera.
   // - this could be done by checking the result of the normalise() function call below.

   // Lots of functions require normalized (unit) direction vectors.
   cameraDirection.normalise();

   // Now we can compute the desired rotation of the player, based on which direction she is pressing the controls.
   Quaternion inputRotation = Quaternion::IDENTITY;
   switch( input )
   {
   case( forward ):
      break;
   case( backward ):
      inputRotation = Quaternion( Degree( 180.f ), Vector3::UNIT_Y );
      break;
   case( left ):
       inputRotation = Quaternion( Degree( 90.f ), Vector3::UNIT_Y );
      break;
   case( right ):
       inputRotation = Quaternion( Degree( -90.f ), Vector3::UNIT_Y );
      break;
   }

   // So the player direction should be the camera direction, rotated by the inputRotation
  Vector3 playerDirection = inputRotation * cameraDirection;

   // In case you need a player orientation as well as a player direction, you can get it like this
   Vector3 playerForwardDefault = Vector3::NEGATIVE_UNIT_Z;   // if your player model isn't facing down the -z axis by default, change this as required.
   Quaternion playerOrientation = playerForwardDefault.getRotationTo( playerDirection, Vector3::UNIT_Y );

   // Now use the playerDirection or playerOrientation to orient and move your character...
Image
drwbns
Orc Shaman
Posts: 788
Joined: Mon Jan 18, 2010 6:06 pm
Location: Costa Mesa, California
x 24

Re: Quaternion multiplication

Post by drwbns »

That looks like it should help. I'll post back if I run into problems, thanks.
User avatar
Kojack
OGRE Moderator
OGRE Moderator
Posts: 7157
Joined: Sun Jan 25, 2004 7:35 am
Location: Brisbane, Australia
x 535

Re: Quaternion multiplication

Post by Kojack »

I noticed that my Sinbad character is actually facing +Z when loaded, is this a rotation problem with the Sinbad character? I'm not rotating the node...
Unfortunately none of the Ogre sample meshes follow standardised dimensions or orientations. The Ninja faces -Z, the robot faces +X and Sinbad faces +Z. They are all different sizes too.
drwbns
Orc Shaman
Posts: 788
Joined: Mon Jan 18, 2010 6:06 pm
Location: Costa Mesa, California
x 24

Re: Quaternion multiplication

Post by drwbns »

lol, I noticed 3d max's covention is different from ogre's as well, I think X and Z are flipped compared to Ogre, not sure, but I noticed it on an export.
User avatar
Kojack
OGRE Moderator
OGRE Moderator
Posts: 7157
Joined: Sun Jan 25, 2004 7:35 am
Location: Brisbane, Australia
x 535

Re: Quaternion multiplication

Post by Kojack »

Yep, Ogre uses right handed Y up. 3DS Max is right handed Z up. Maya is right handed Y up but can switch to Z up.
UDK is left handed Z up. Unity3D is left handed Y up.
Quake3 is right handed Z down, which is just odd.