Information on Quaternions
-
Clay
- OGRE Community Helper

- Posts: 518
- Joined: Wed Mar 17, 2004 4:14 am
- x 1
Information on Quaternions
I could ask about 100 questions related to Quaternions, but lets cut to the heart of the matter.
Does anyone have a good reference for Quaternions in their application to Ogre/3D graphics programming they could link me? Mathworld and Wikipedia have very specific information pertaining to the underlying math (which I am going to read after I finish this post), but is there a good "getting started" guide that would be useful?
Thanks.
Does anyone have a good reference for Quaternions in their application to Ogre/3D graphics programming they could link me? Mathworld and Wikipedia have very specific information pertaining to the underlying math (which I am going to read after I finish this post), but is there a good "getting started" guide that would be useful?
Thanks.
-
Clay
- OGRE Community Helper

- Posts: 518
- Joined: Wed Mar 17, 2004 4:14 am
- x 1
-
Clay
- OGRE Community Helper

- Posts: 518
- Joined: Wed Mar 17, 2004 4:14 am
- x 1
Already read it. =)
I guess I'll just post a specific question. I have the same problem this guy was having http://www.ogre3d.org/phpBB2/viewtopic. ... quaternion. I have a character sitting in space, and I need him to face the direction I'm moving him.
I have a unit vector in the direction that I want him to face mDirection, and his SceneNode mNode. What I think I need to do is call: mNode->yaw( angle );
However, I don't know how to calculate that angle. Is this the right way to aproach this? From the post I linked above, Sinbad seems to suggest I should be using Quaternions instead of trying to yaw the SceneNode, but I am having trouble finding documentation on how to use Slerp. http://www.ogre3d.org/docs/api/html/cla ... aterniond0 does not have any explination.
I also tried this:
but even if this correctly gets the Quatrernion I want, I have no idea what to do with the quat variable to rotate the scene node.
Any ideas?
I guess I'll just post a specific question. I have the same problem this guy was having http://www.ogre3d.org/phpBB2/viewtopic. ... quaternion. I have a character sitting in space, and I need him to face the direction I'm moving him.
I have a unit vector in the direction that I want him to face mDirection, and his SceneNode mNode. What I think I need to do is call: mNode->yaw( angle );
However, I don't know how to calculate that angle. Is this the right way to aproach this? From the post I linked above, Sinbad seems to suggest I should be using Quaternions instead of trying to yaw the SceneNode, but I am having trouble finding documentation on how to use Slerp. http://www.ogre3d.org/docs/api/html/cla ... aterniond0 does not have any explination.
I also tried this:
Code: Select all
Ogre::Vector3 src = mNode->getOrientation() * Ogre::Vector3::UNIT_Z;
Ogre::Quaternion quat = src.getRotationTo( mDirection );Any ideas?
-
DWORD
- OGRE Retired Moderator

- Posts: 1365
- Joined: Tue Sep 07, 2004 12:43 pm
- Location: Aalborg, Denmark
You are nearly there. 
rkP and rkQ are source and destination orientations, and fT is a value from 0 to 1 describing the transition (0 = source, 1 = destination, or any value inbetween). shortestPath specifies whether to use the shortest path. 
Edit: Ouch, that's not correct... src.getRotationTo() returns 'the shortest arc quaternion to rotate this vector to the destination vector'. So you'll have to use mNode->getOrientation()*quat as your destination quaternion. I hope I got it right this time...
Code: Select all
Quaternion Ogre::Quaternion::Slerp(Real fT, const Quaternion &rkP, const Quaternion &rkQ, bool shortestPath = false);Now you just use the original mNode->getOrientation() as your source (rkP) quaternion, and quat as your destination (rkQ) quaternion. By linearly interpolating fT from 0 to 1 over time in Ogre::Quaternion::Slerp(), you get an intermediate quaternion, which you can use for your scene node's orientation. Hth.I also tried this:
but even if this correctly gets the Quatrernion I want, I have no idea what to do with the quat variable to rotate the scene node.Code: Select all
Ogre::Vector3 src = mNode->getOrientation() * Ogre::Vector3::UNIT_Z; Ogre::Quaternion quat = src.getRotationTo( mDirection );
Edit: Ouch, that's not correct... src.getRotationTo() returns 'the shortest arc quaternion to rotate this vector to the destination vector'. So you'll have to use mNode->getOrientation()*quat as your destination quaternion. I hope I got it right this time...
-
haffax
- OGRE Retired Moderator

- Posts: 4823
- Joined: Fri Jun 18, 2004 1:40 pm
- Location: Berlin, Germany
- x 8
You can apply the Quaternion with SceneNode::rotate().
If nNode has not the the root node as its parent, make sure you use the correct transform space. When mDirection is a direction in world space, then you first need to apply mNodes world orientation to it, before getting the rotation.
(From the top of my head. So there might be errors in it)
If nNode has not the the root node as its parent, make sure you use the correct transform space. When mDirection is a direction in world space, then you first need to apply mNodes world orientation to it, before getting the rotation.
Code: Select all
Vector3 transDir = mNode->getWorldOrientation() * mDirection;
-
Van
- Hobgoblin
- Posts: 512
- Joined: Fri Nov 19, 2004 3:56 am
Clay,
I hope you have better luck than me in getting your problem to work.
I took this example and did the following:
The Goal
Point NodeArrowTargetVector SceneNode at CurrentTarget SceneNode.
Result
In one frame, the NodeArrowTargetVector does point at the target. In the next frame is points off into space. On the next frame, it poinsts at the target, and so on, and so on...
I can not see what I am doing wrong. The math keeps coming up with two different solutions (one per frame) causing the arrow to jump back and forth between the two solutions (ie. each frame).
Can someone see what is wrong with this math?
I hope you have better luck than me in getting your problem to work.
I took this example and did the following:
Code: Select all
// Code to get SceneNode "NodeArrowTargetVector" to point at SceneNode "CurrentTarget"
Ogre::Vector3 srcNodeVector = NodeArrowTargetVector->getWorldOrientation() * Ogre::Vector3::NEGATIVE_UNIT_Z;
Ogre::Quaternion destNodeQuant = srcNodeVector.getRotationTo( MySpaceShip->CurrentTarget->Node->getWorldPosition() );
Ogre::Quaternion srcNewOrientationQuat = Ogre::Quaternion::Slerp(
1,
NodeArrowTargetVector->getWorldOrientation(),
MySpaceShip->CurrentTarget->Node->getWorldOrientation() * destNodeQuant,
true);
// Change NodeArrowTargetVector Orientation to now point at CurrentTarget SceneNode
NodeArrowTargetVector->setOrientation(srcNewOrientationQuat);
Point NodeArrowTargetVector SceneNode at CurrentTarget SceneNode.
Result
In one frame, the NodeArrowTargetVector does point at the target. In the next frame is points off into space. On the next frame, it poinsts at the target, and so on, and so on...
I can not see what I am doing wrong. The math keeps coming up with two different solutions (one per frame) causing the arrow to jump back and forth between the two solutions (ie. each frame).
Can someone see what is wrong with this math?
-
Robomaniac
- Hobgoblin
- Posts: 508
- Joined: Tue Feb 03, 2004 6:39 am
-
Van
- Hobgoblin
- Posts: 512
- Joined: Fri Nov 19, 2004 3:56 am
-
sinbad
- OGRE Retired Team Member

- Posts: 19269
- Joined: Sun Oct 06, 2002 11:19 pm
- Location: Guernsey, Channel Islands
- x 67
Actually it's exactly 180 degrees that has the problem, and the reason is that there are an infinite number of rotations that can perform the lookAt in that case, therefore the 'up' vector could go almost anywhere. Just try doing it with a model plane or something - point it exactly 180 degrees away from the target and then tell me how you decide how to rotate it to point the other way. Sure, you might intuitively use a yaw but Ogre can't know that - it could yaw, it could pitch, it could do any one of an infinite number of rotations, each one resulting in the plane pointing the other way, but with an infinite number of roll positions. You have to special case this situation, we can't do it for you.
For example:
For example:
Code: Select all
Real d = 1.0f + olddirection.dotProduct(newdirection);
if (fabs(d) < 0.00001)
{
// Diametrically opposed vectors
// How you resolve this depends on your application
// Options include a 180 degree yaw, a 180 degree rotate around the
// axis of momentum, etc
}
else
{
node->lookAt(newdirection);
}
-
Clay
- OGRE Community Helper

- Posts: 518
- Joined: Wed Mar 17, 2004 4:14 am
- x 1
Thanks! This worked perfectly. For those of you that find this thread later:
The following code does the job:
I have only two final questions:
1) In the above code, I understand the difference between nlerp and Slerp. What I don't understand is the difference between rotate and setOrientation. When I use either of them, they take me to the correct direction, should I be specifically using one of them in the above code?
2) The constant UNIT_Z is seems arbitrary. I understand you need to multiply by SOME vector to get the correct direction, but why UNIT_Z? Is this the default facing of an object in Ogre?
~~~
When I get these things figured out, I'm going to update the wiki with this information.
Edit: The above will fail if this is supposed to be a 180 degree rotation correct? If so I can update the code to handle that special case (and use a dot product to determine when the lines are parallel).
Edit2: Actually that was backwards, I needed NEGATIVE_UNIT_Z, not UNIT_Z.
The following code does the job:
Code: Select all
Ogre::Vector3 src = mNode->getWorldOrientation() * Ogre::Vector3::NEGATIVE_UNIT_Z;
Ogre::Quaternion quat = src.getRotationTo( mDirection );
mNode->rotate( Ogre::Quaternion::Slerp(1.0f, mNode->getWorldOrientation(), quat, true ) );
// The last line could also be:
//mNode->rotate( Ogre::Quaternion::nlerp(1.0f, mNode->getWorldOrientation(), quat, true ) );
//mNode->setOrientation( Ogre::Quaternion::Slerp(1.0f, mNode->getWorldOrientation(), quat, true ) );
//mNode->setOrientation( Ogre::Quaternion::nlerp(1.0f, mNode->getWorldOrientation(), quat, true ) );
1) In the above code, I understand the difference between nlerp and Slerp. What I don't understand is the difference between rotate and setOrientation. When I use either of them, they take me to the correct direction, should I be specifically using one of them in the above code?
2) The constant UNIT_Z is seems arbitrary. I understand you need to multiply by SOME vector to get the correct direction, but why UNIT_Z? Is this the default facing of an object in Ogre?
~~~
When I get these things figured out, I'm going to update the wiki with this information.
Edit: The above will fail if this is supposed to be a 180 degree rotation correct? If so I can update the code to handle that special case (and use a dot product to determine when the lines are parallel).
Edit2: Actually that was backwards, I needed NEGATIVE_UNIT_Z, not UNIT_Z.
Last edited by Clay on Wed Jan 26, 2005 1:51 am, edited 1 time in total.
-
sinbad
- OGRE Retired Team Member

- Posts: 19269
- Joined: Sun Oct 06, 2002 11:19 pm
- Location: Guernsey, Channel Islands
- x 67
-
Clay
- OGRE Community Helper

- Posts: 518
- Joined: Wed Mar 17, 2004 4:14 am
- x 1
-
haffax
- OGRE Retired Moderator

- Posts: 4823
- Joined: Fri Jun 18, 2004 1:40 pm
- Location: Berlin, Germany
- x 8
Well, many projects (like our) use -Z as the default facing direction. All models are created this way. In the standard right handed coordinate system, that Ogre uses, -Z points "into the monitor". So this choice comes naturally and for methods that take a facing (like lookAt()) NEGATIVE_UNIT_Z is the default parameter.
(I guess you actually mean NEGATIVE_UNIT_Z not UNIT_Z)
The difference between rotate() and setOrientation() is, that rotate() applies the rotation relative to the current orientation in the specified transform space, whereas setOrientation() sets the given rotation relative to the parent node's orientation. This does not depend on the node's former orientation.
(I guess you actually mean NEGATIVE_UNIT_Z not UNIT_Z)
The difference between rotate() and setOrientation() is, that rotate() applies the rotation relative to the current orientation in the specified transform space, whereas setOrientation() sets the given rotation relative to the parent node's orientation. This does not depend on the node's former orientation.
-
y721
- Gremlin
- Posts: 153
- Joined: Mon Nov 08, 2004 3:15 am
- Location: Taiwan
Hi:
I have 2 questions:
Frist is regarding Quaternion * vector3.
and what about v' = q * v * q', (q' is conjugate of q), I found the fomula in several resources.
The other is regarding interpolation.
Would it be replaced with
mNode->rotate (quat);
Thank you.

I have 2 questions:
Frist is regarding Quaternion * vector3.
Does v' = q * v mean that v is rotated by q? If it's true, would the node's up vector be q * UNIT_Y?Ogre::Vector3 src = mNode->getWorldOrientation() * Ogre::Vector3::NEGATIVE_UNIT_Z;
and what about v' = q * v * q', (q' is conjugate of q), I found the fomula in several resources.
The other is regarding interpolation.
Since the parameter is 1.0f, function Slerp () = quat.Ogre::Quaternion quat = src.getRotationTo( mDirection );
mNode->rotate( Ogre::Quaternion::Slerp(1.0f, mNode->getWorldOrientation(), quat, true ) );
Would it be replaced with
mNode->rotate (quat);
Thank you.
-
DWORD
- OGRE Retired Moderator

- Posts: 1365
- Joined: Tue Sep 07, 2004 12:43 pm
- Location: Aalborg, Denmark
Yes, that's correct. I can't answer your question on v' = q * v * q', though.y721 wrote:Does v' = q * v mean that v is rotated by q? If it's true, would the node's up vector be q * UNIT_Y?Ogre::Vector3 src = mNode->getWorldOrientation() * Ogre::Vector3::NEGATIVE_UNIT_Z;
I also thought about this, and I'm pretty sure it's the same, so Slerp() should really be substitued because it isn't really needed. I didn't have the chance to try this code myself, though, so I wouldn't post any unqualified guesses.y721 wrote:The other is regarding interpolation.Since the parameter is 1.0f, function Slerp () = quat.Ogre::Quaternion quat = src.getRotationTo( mDirection );
mNode->rotate( Ogre::Quaternion::Slerp(1.0f, mNode->getWorldOrientation(), quat, true ) );
Would it be replaced with
mNode->rotate (quat);
-
DWORD
- OGRE Retired Moderator

- Posts: 1365
- Joined: Tue Sep 07, 2004 12:43 pm
- Location: Aalborg, Denmark
The point in using the Slerp() function would be to interpolate the rotation over time, so that we could get a smooth turn. This would require two quaternions, which we almost already have: a source quaternion which is the original orientation, and a destination quaternion which is the wanted orientation. Warning: Untested code.
Note that it's still necessary to special-case a near 180° rotation. Now we can interpolate over time to get a smooth rotation of the node. E.g. in a frame listener:
Now we only need to change t over time from 0 to 1.
Edit: Clarifications.
Code: Select all
// Get the node's original orientation
Quaternion srcOrientation = node->getOrientation();
// Calculate the node's original direction (in world space)
Vector3 srcDirection = node->getWorldOrientation() * Vector3::NEGATIVE_UNIT_Z;
// Assume that dstDirection is the wanted direction in world space,
// and calculate the necessary rotation.
Quaternion rotation = srcDirection.getRotationTo(dstDirection);
// Calculate wanted destination orientation
Quaternion dstOrientation = srcOrientation * rotation;Code: Select all
node->setOrientation(Quaternion::Slerp(t, srcOrientation, dstOrientation));Edit: Clarifications.
Last edited by DWORD on Sat Jan 29, 2005 4:54 pm, edited 2 times in total.
-
haffax
- OGRE Retired Moderator

- Posts: 4823
- Joined: Fri Jun 18, 2004 1:40 pm
- Location: Berlin, Germany
- x 8
That's what Quaternion::operator*(const Vector3&) does effectivly. Only that this formula is already remodeled. Just write this equation component wise and you see you can convert it to Ogre's implementation.y721 wrote: and what about v' = q * v * q', (q' is conjugate of q), I found the fomula in several resources.
-
Clay
- OGRE Community Helper

- Posts: 518
- Joined: Wed Mar 17, 2004 4:14 am
- x 1