Why people are scared from quaternions ?

Started by
2 comments, last by silvia_steven_2000 18 years, 9 months ago
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
Advertisement
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){#if DEBUG	float sqrLen1 = v1.LengthSq();	float sqrLen2 = v2.LengthSq();	System.Diagnostics.Debug.Assert(sqrLen1 > 1 - ZeroTolerence && sqrLen1 < 1 + ZeroTolerence &&			                sqrLen2 > 1 - ZeroTolerence && sqrLen2 < 1 + ZeroTolerence,	                                MsgVecNonNormalized);#endif	// 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;	bisector.Normalize();	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		//cross.Normalize();	}#if DEBUG	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);#endif	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 geometrictools.com [smile]
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,
-------------------------------------------------------------------Life is short so go on and live it, cause the chicks dig it.- Kahsm
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.

This topic is closed to new replies.

Advertisement