Quaternions and the toEuler function

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
Post Reply
LittleGiant
Posts: 15
Joined: Wed Jun 02, 2004 1:53 am

Quaternions and the toEuler function

Post by LittleGiant »

I'm attempting to maintain a quaternion rotation and use it to set the rotation on a scene node

Code: Select all

Rotate( const quaternion4f& vRot )
{ 
	vector3f v;
	vRot .toEuler( v );
	v *= RADTODEG;
	pSceneNode->setRotation( v );
}
All seems fine right up until toEuler populates my vector with an undefined number.

Example quat values that cause this:
X 0.00000000
Y 0.70710683
Z 0.00000000
W 0.70710683

This code:

Code: Select all

	// attitude = rotation about y-axis
	euler.Y = (f32) (asin(-2.0 * (X*Z - Y*W)));
uses asin obviously which has certain acceptable range.

Code: Select all

// attitude = rotation about y-axis
	euler.Y = (f32) (asin( clamp(-2.0 * (X*Z - Y*W), -1.0, 1.0) ));
looking into this more i see that 1.4 uses the above, i'm on 1.3.1 currently.

i wonder if this is enough to handle the issues and give you good results, researching it more i've seen implimentations like:

Code: Select all

public void set(Quat4d q1) {
    double sqw = q1.w*q1.w;
    double sqx = q1.x*q1.x;
    double sqy = q1.y*q1.y;
    double sqz = q1.z*q1.z;
	double unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor
	double test = q1.x*q1.y + q1.z*q1.w;
	if (test > 0.499*unit) { // singularity at north pole
		heading = 2 * atan2(q1.x,q1.w);
		attitude = Math.PI/2;
		bank = 0;
		return;
	}
	if (test < -0.499*unit) { // singularity at south pole
		heading = -2 * atan2(q1.x,q1.w);
		attitude = -Math.PI/2;
		bank = 0;
		return;
	}
    heading = atan2(2*q1.y*q1.w-2*q1.x*q1.z , sqx - sqy - sqz + sqw);
	attitude = asin(2*test/unit);
	bank = atan2(2*q1.x*q1.w-2*q1.y*q1.z , -sqx + sqy - sqz + sqw)
}
Would someone more mathematically savvy then me enlighten me at to whether or not the clamp is a good solution?

Thanks in advance,
LG

PS: ignore the types i'm using in the first code example assume they are what your used to cause they are exactly that ( typedef'd )
morris
Posts: 36
Joined: Tue Jul 10, 2007 10:10 am

Post by morris »

SQRT(0.5) is approximately 0.7071067811.

the quaternion you pasted has Y=0.70710683 and W=0.70710683 which are slightly bigger than SQRT(0.5).

therefore: Y*W > 0.5, and therefore -2.0*(Y*W) > -1.0, and therefore asin(-2.0*(Y*W)) is undefined.

you might want to try to normalise the quaternions instead of clamping. i don't remember how to do that, but this page might be helpful.

where do you get the quaternions from? physics? because maybe there are also functions to get transformation matrices which are a lot easier to use with irrlicht.
Post Reply