Z Axis Issue with Quaternion to Euler Angle Conversion Function

Started by
1 comment, last by Klokwerk 13 years, 4 months ago
Greetings,

I’m trying to build a quaternion based rotational camera demo and I want the UI to display the Euler angles of the camera.

This made me create the following function for converting the orientation quaternion into Euler angles, expressed in radians and converted into degrees within the function.

However the Z axis doesn’t come out right. The X and Y axes output the correct rotation, but the Z axis comes out with somewhat random expressions depending on the rotation of the X and Y axes.

I think I may be able to simply process the data in a similar way but in a different order to get the correct output of the camera’s roll, but if anyone has an idea on how to do so I would be grateful.

D3DXVECTOR3 cCamera::QuaternionToEuler( D3DXQUATERNION q )
{

D3DXVECTOR3 v ;

v.x = (float)atan2 ( 2 * q.y * q.w - 2 * q.x * q.z, 1 - 2 * pow(q.y, 2) - 2 * pow(q.z, 2) ) ;
v.z = (float)asin ( 2 * q.x * q.y + 2 * q.z * q.w ) ;
v.y = (float)atan2 ( 2 * q.x * q.w - 2 * q.y * q.z, 1 - 2 * pow(q.x, 2) - 2 * pow(q.z, 2) ) ;

if ( q.x * q.y + q.z * q.w == 0.5 ) { v.x = (float)( 2 * atan2( q.x, q.w ) ) ; v.y = 0 ; }
else if ( q.x * q.y + q.z * q.w == -0.5 ) { v.x = (float)( -2 * atan2( q.x, q.w ) ) ; v.y = 0 ; }

if ( v.x > 0 ) { v.x = RADTODEG( v.x ) ; } else if ( v.x < 0 ) { v.x = RADTODEG( ( v.x + ( PI * 2 ) ) ) ; }
if ( v.y > 0 ) { v.y = RADTODEG( v.y ) ; } else if ( v.y < 0 ) { v.y = RADTODEG( ( v.y + ( PI * 2 ) ) ) ; }
if ( v.z > 0 ) { v.z = RADTODEG( v.z ) ; } else if ( v.z < 0 ) { v.z = RADTODEG( ( v.z + ( PI * 2 ) ) ) ; }

return v ;

}

Cheers.
/Klok
Advertisement
You can certainly swap the order around to see if you can get something that seems more reasonable, but IMHO, the endeavor is probably a bit misguided in the first place.

First, let me ask this: what's the control scheme for the camera object? 6DOF? FPS-style? Something else?

Second, conversions from representations such as matrices or quaternions to Euler angles is always a bit iffy; depending on how the conversion function is implemented, you may or may not get the angles you expect or angles that make intuitive sense to you. You can narrow things down a bit by using so-called 'canonical' Euler angles, but the results still might not be particularly intuitive (depending on what you're expecting).
Not that Im expecting any further responses to this thread, but I've since resolved the issue and got the correct readout from the Z axis.

In response to JYK:

I think I may have used the wrong terms. Forgive me but I'm a writer and a designer, not a mathematician nor someone who regularly works with graphical programming.

What I was trying to do was convert the quaternion information, values which range from -2 to 2, that represents the cameras rotational orientation into a single vector which can be used to express the camera's rotation in degrees, hence the degree to raiden conversion in the latter stage of the function.

The issue I had was that the output of the function I posted returned the rotation, expressed in degrees from 0-360, around the X and Y axis (the yaw and pitch) but did not return the 0-360 rotation around the Z axis.

As I say I resolved this, and I did so by using Atan2 on the Z axis, thus:

D3DXVECTOR3 cCamera::QuaternionToEuler( D3DXQUATERNION q )
{
D3DXVECTOR3 v ;

v.x = QTE_atan2 ( q.y, q.w, q.x, q.z ) ;
v.z = QTE_atan2 ( q.z, q.w, q.y, q.x ) ;
v.y = QTE_atan2 ( q.x, q.w, q.y, q.z ) ;

if ( q.x * q.y + q.z * q.w == 0.5 ) { v.x = (float)( 2 * atan2( q.x, q.w ) ) ; v.y = 0 ; }
else if ( q.x * q.y + q.z * q.w == -0.5 ) { v.x = (float)( -2 * atan2( q.x, q.w ) ) ; v.y = 0 ; }

v.x = QTE_ConvertRadToDeg( v.x ) ;
v.y = QTE_ConvertRadToDeg( v.y ) ;
v.z = QTE_ConvertRadToDeg( v.z ) ;

return v ;
}

As a point of interest; my camera class and indeed my program firstly allows the user to see how each of the different kinds of camera perspectives work in practise and then how to build said cameras though examination of the code.

The program itself is the practical aspect of my book on computer game camera perspectives which covers the entire gamut from first person to all variants of the third person perspective.

The actual camera perspective and its control schemata has no bearing on the conversion function however, and I know this given that I consistently receive the correct output on the UI which indicates the cameras rotation on all three axes, which itself is based on the data contained within the rotational quaternion.

This is to say that the converted rotation is perfectly precise, just as the rotation itself is perfectly precise to the world axes, but of course I display them as integers rather than floats as I also display the full rotational matrix's data as well - the output of this function is for the user to understand what approximate angle they have rotated to rather than anything precise to the decimal place.

Anyway, job done. I was perhaps a little hasty in my public request for assistance. ;)

/Klok

This topic is closed to new replies.

Advertisement