Sign in to follow this  

Why people are scared from quaternions ?

Recommended Posts

Hi All I have spent allot of time trying to resolve my problem but I could not find a solution. I posted my question on game programming forum but no body helped. may be they are scared from quaternions. I am using directx so the coordinate system is left handed where the positive z axis goes into the screen. I am trying to build a simple camera. I am given the up vector, the position of the camera and the target to look at. with this information in hand, it is very easy to build a left handed look at matrix, I already did that but this is not what I want. my scene nodes including cameras have their orientaions stored as quaternions. wheneve I need to animate a node I manipulate the orientaion quaternion then finally it gets converted into a world transform. this is working fine with me but I could not make it work in case of camera. the same way I need to manipulate the camera orientation quaternion and finally convert it to a view transform. sorry for the long explanation but I think it might help. here is what I did : the view transfom is the inverse of the transform needed to move the camera position to the origin and realign the camera look, up and right with the z, u and x axes //Set camera position m_relPos = camPos //up vector m_up.Normalize(); //Calculate look at vector //m_relPos below should be the absolute pos but here //I am assuming the camera has no parent m_look = m_target - m_relPos //Normalize the look vector m_look.Normalize(); //Quaternion to rotate the look to z core::Quaternion look2z; //Quaternion to rotate the up to y core::Quaternion up2y; //calculate look2z look2z = look2z.getRotationTo(m_look, core::Vector3::UNITZ); //calculate up2y up2y = up2y.getRotationTo(m_up, core::Vector3::UNITY); //Update camera orientation m_relOrient = look2z * up2y; so far the camera m_relPos and m_relOrient are there convert the m_relOrient to rotation matrix and set the translation to m_relPos and store it in m_relTransform //Calculate view transform as: m_view = m_relTransform.getInverse(); what is really confusing me is that I guess there is something tricky here. for example: if we look at the origin from the positions: camPos ==== (-10, 0, 0); ok (-10, 10, 0); ok (-10, 0, -10); ok (-10, 10, -10); view is shifted or rotated (0, 0, -10); ok (0, 10, -10); view is shifted or rotated (10, 0, -10); ok (10, 10, -10); view is shifted or rotated (10, 0, 0); ok (10, 10, 0); ok it does not work only in the cases where the y and z of the look vector are both non zero. I can not find an explanation for this. I am suspicious about the fact that direct x is a left handed system while the quaternion math assumes right handed system. sorry for the long message, I entended to do that to make things clear. any help is appreciated thanks again

Share this post

Link to post
Share on other sites
DrGUI    402
I'd be interested if you got it to work because I only orientate my model's z along the look-at vector but after a while it goes upside-down because I don't know how to orientate it in 2 directions at once :(

Here's my quaternion code which works [smile]
You can ignore the #if DEBUG sections if you want - that's just to ensure that my code is passing in normalized vectors and that the result is a normalized quaternion.

/// <summary>
/// Computes a quaternion that rotates unit-length vector v1 to unit-length vector v2. The rotation is about
/// the axis perpendicular to both v1 and v2, with angle of that between v1 and v2. If v1 and v2 are parallel,
/// any axis of rotation is used, such as the permutation (v2.Z,v2.X,v2.Y).</summary>
/// <param name="v1">Normalized vector that the computed quaternion rotates from to v2.</param>
/// <param name="v2">Normalized vector that the computed quaternion rotates to from v1.</param>
/// <returns>A quaternion that rotates v1 to v2.</returns>
public static Quaternion Align(Vector3 v1, Vector3 v2)
float sqrLen1 = v1.LengthSq();
float sqrLen2 = v2.LengthSq();
System.Diagnostics.Debug.Assert(sqrLen1 > 1 - ZeroTolerence && sqrLen1 < 1 + ZeroTolerence &&
sqrLen2 > 1 - ZeroTolerence && sqrLen2 < 1 + ZeroTolerence,
// If V1 and V2 are not parallel, the axis of rotation is the unit-length
// vector U = Cross(V1,V2)/Length(Cross(V1,V2)). The angle of rotation,
// A, is the angle between V1 and V2. The quaternion for the rotation is
// q = cos(A/2) + sin(A/2)*(ux*i+uy*j+uz*k) where U = (ux,uy,uz).
// (1) Rather than extract A = acos(Dot(V1,V2)), multiply by 1/2, then
// compute sin(A/2) and cos(A/2), we reduce the computational costs by
// computing the bisector B = (V1+V2)/Length(V1+V2), so cos(A/2) =
// Dot(V1,B).
// (2) The rotation axis is U = Cross(V1,B)/Length(Cross(V1,B)), but
// Length(Cross(V1,B)) = Length(V1)*Length(B)*sin(A/2) = sin(A/2), in
// which case sin(A/2)*(ux*i+uy*j+uz*k) = (cx*i+cy*j+cz*k) where
// C = Cross(V1,B).
Vector3 bisector = v1 + v2;
float cosHalfAngle = Vector3.Dot(v1, bisector);
Vector3 cross;
if (cosHalfAngle > ZeroTolerence || cosHalfAngle < -ZeroTolerence) {
cross = Vector3.Cross(v1, bisector);
} else {
cross = Vector3.Cross(v1, new Vector3(v2.Z, v2.X, v2.Y));
//cosHalfAngle = 0.0f; - already is very close

float sqrLen = cross.X*cross.X+cross.Y*cross.Y+cross.Z*cross.Z+cosHalfAngle*cosHalfAngle;
System.Diagnostics.Debug.Assert(sqrLen > 1 - ZeroTolerence && sqrLen < 1 + ZeroTolerence);
return new Quaternion(cross.X, cross.Y, cross.Z, cosHalfAngle);

EDIT: Also I should probably mention that I based that on the C++ code on [smile]

Share this post

Link to post
Share on other sites
Kahsm    302
Hello silvia_steven_2000,

I see you are using...

core::Quaternion up2y;

... to define a quaternion. Are you not using the built in DirectX Quaternions?

If you are not using the DirectX quaternion, then your fear is quite possible. OpenGL does not have a built in quaternion structure so odds are probably fairly good that your custom quat was written to be right-handed.

If you are using the DirectX quaternion and just wrapped it up, then it will already have been adjusted for left-handed co-ords.

As per your specific problem I can not say what's wrong.

Good Luck,

Share this post

Link to post
Share on other sites
thanks DrGUI for the code, actually I have no problem with that since I already have the code the finds the quaternion to rotate a vector to a vector. but there is something wrong in the way I rotate the look and up vectors.
regarding the dx quaternion class. thanks for the hint but I doubt it is gonna change something, I have a good quaternion class. I think my problem is in the login I am using. look at this statement: the view transform is basically the inverse of the transform needed to translate the camera position to the origin and re-orient its local coordinates with the world x , y and z. I am trying to implement that. rotate the look to -z and up to y but it does work in some cases and does not wrok in the other cases. there should be something stupid that I am not paying attention to since in the cases where it does not work I can see the objects I am looking to but there are not in the middle of the screen. the camera is like shifted or missoriented.

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this