Page 1 of 1

Quaternions and the toEuler function

Posted: Thu Feb 14, 2008 8:06 am
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 )

Posted: Thu Feb 14, 2008 9:24 pm
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.