Quaternions to Euler and vice versa[solved]

Get answers to all your basic programming questions. No Ogre questions, please!
MaxPal3D
Gnoblar
Posts: 15
Joined: Tue Mar 13, 2007 12:46 pm
x 1

Quaternions to Euler and vice versa[solved]

Post by MaxPal3D »

I don't know whether this is a basic question, but have stuck with quaternions. I moved to OGRE with existing code that uses Euler angels and to maintain backward compatibility I decided to convert rotation data to quaternions before give them to OGRE and then convert rotation back again. I've heard about problems when pitch approaches +-90 degrees but don't know how to manage them. I based my code on matrix conversions mentioned here on forum and used system similar to that in OgreNewt. Here is my test code on which I based my functions(it tests conversion to quaternion and backwards):

Code: Select all

		vector3df someIrrVect(390, 89, 219);
		matrix4 matrixIrr, matrixIrr2;
		//matrixIrr.makeIdentity();
		matrixIrr.setRotationDegrees(someIrrVect);

		Quaternion quat = Quaternion( Matrix3(	matrixIrr[0], matrixIrr[4], matrixIrr[8],
			matrixIrr[1], matrixIrr[5], matrixIrr[9],
			matrixIrr[2], matrixIrr[6], matrixIrr[10] ) );

		//quat.normalise();
		Matrix3 rot;
		Vector3 xcol, ycol, zcol;
		quat.ToRotationMatrix( rot );	// creates a 3x3 rotation matrix from the Quaternion.

		xcol = rot.GetColumn(0);
		ycol = rot.GetColumn(1);
		zcol = rot.GetColumn(2);

		//matrixIrr2.makeIdentity();
		// now fill the final matrix with the appropriate data:
		matrixIrr2[0] = xcol.x;
		matrixIrr2[1] = xcol.y;
		matrixIrr2[2] = xcol.z;
		matrixIrr2[3] = 0.0f;

		matrixIrr2[4] = ycol.x;
		matrixIrr2[5] = ycol.y;
		matrixIrr2[6] = ycol.z;
		matrixIrr2[7] = 0.0f;

		matrixIrr2[8] = zcol.x;
		matrixIrr2[9] = zcol.y;
		matrixIrr2[10] = zcol.z;
		matrixIrr2[11] = 0.0f;

		vector3df result = matrixIrr2.getRotationDegrees();
But it works wrong. It gives write data in some diapason and wrong in other. But I cannot strip my data before Ogre input and cannot glue them afterwards it messes all rotations. I saw that it is possible to make conversions as described e.g. here http://en.wikipedia.org/wiki/Conversion ... ler_angles
but all that math pushes me out. May be there is some blackbox decision that handles all calculations and deals with quaternion's particular features internally? And whats wrong with that code?
Last edited by MaxPal3D on Mon Dec 10, 2007 1:30 am, edited 1 time in total.
User avatar
Bontakun
Goblin
Posts: 290
Joined: Tue Dec 09, 2003 6:09 am
Location: Melbourne, Australia

Post by Bontakun »

Tried Matrix3::FromEulerAnglesYXZ() ?
- Bonta (eveonline:Dentad)
MaxPal3D
Gnoblar
Posts: 15
Joined: Tue Mar 13, 2007 12:46 pm
x 1

Post by MaxPal3D »

Tried Matrix3::FromEulerAnglesYXZ() ?
Yes, but in fact following code fails even in more cases than my previous:

Code: Select all

Matrix3 mx, mx2;
		mx.FromEulerAnglesXYZ(Degree(190), Degree(89), Degree(230));
		Quaternion sum(mx); 
		sum.ToRotationMatrix(mx2);
		Radian x, y, z;
		mx2.ToEulerAnglesXYZ(x, y, z);
		vector3df vect(x.valueAngleUnits(), y.valueAngleUnits(), z.valueAngleUnits());//The result is(-170, 89, -129) and thats already wrong, not even exceeding y value
CABAListic
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 2903
Joined: Thu Jan 18, 2007 2:48 pm
x 58

Post by CABAListic »

What's wrong with the result? It's giving you the same angles as you put into (with -129 being a slight rounding error), just in the range from [-180, 180]. -170 is the same as 190.

If you wish, just do a

Code: Select all

(angle + 360) % 360
on the angles, and you'll get the remapped results...
MaxPal3D
Gnoblar
Posts: 15
Joined: Tue Mar 13, 2007 12:46 pm
x 1

Post by MaxPal3D »

What's wrong with the result? It's giving you the same angles as you put into (with -129 being a slight rounding error), just in the range from [-180, 180]. -170 is the same as 190.
Yes, now I see that's the same, but what to do with Euler singularities? A lot of objects are rotated with y > 90. I saw workaround for camera, but it couldn't be generalized, You cannot attach some additional nodes every time to apply rotation. How e. g. I can apply rotation [120, 140, 320]?
alanic
Gnoblar
Posts: 14
Joined: Wed Dec 05, 2007 9:40 pm

Post by alanic »

FWIW, Euler angles to quaternions conversion is a well defined function, but the inverse is not because Euler angles are ambiguous at certain rotations (i.e. it is possible to have more than one Euler angle values for some rotation matrices, (with the same Euler angle ordering) ). So I think if you use Ogre's built in conversions you should be fine.

So, when you do Euler angles -> quaternions -> Euler angles, the values of the result do not have to be the same with the Euler angles you started out with since Euler angles are ambiguous. But what you see should be the same rotation.
MaxPal3D
Gnoblar
Posts: 15
Joined: Tue Mar 13, 2007 12:46 pm
x 1

Post by MaxPal3D »

I have debugged my program more thoroughly and discovered that problem is exactly because ogre is inversing angles internally. This is correct mathematically but wrong for outer algorithm.
That's how it looks:
1) Euler based code sets initial objects angles
2) Those data are converted to quaternions and feed to Ogre
3) Ogre repositions nodes and render
4) Euler based code fetches rotation data and converts to angles calculates and feeds back to Ogre

Now real world data:

Initial rotation:
X: 1.953043 Y: 89.55063 Z: -2.721484e-005;
Calculate and Sending data to Ogre:
X: 1.953043 Y: 89.94125 Z: -2.721484e-005;
Getting from Ogre:
X: 1.95293 Y: 89.94065 Z: -0.000104075;
Now its ok, the angles are as expected.
Calculate and Sending data to Ogre:
X: 1.95293 Y: 90.23362 Z: -0.000104075;//!Yaw over 90 degrees!!!
Getting from Ogre:
X: -178.0471 Y: 89.76593 Z: 179.9999;
Ooops... That is approximately the same, but Euler based algorithm cannot distinguish that numbers substituted. Based on this we will calculate next quaternion with orientation.
Calculate and Sending data to Ogre:
X: -178.0471 Y: 89.76593 Z: 179.9999;

Next frame we see Ogre also didn't expect: the object is upside down, the robot is walking on the sky!

And the worst thing is that I cannot determine when angles have been inverted.
User avatar
Bontakun
Goblin
Posts: 290
Joined: Tue Dec 09, 2003 6:09 am
Location: Melbourne, Australia

Post by Bontakun »

@MaxPal3D
I suggest you use quaternions more often in your code to avoid the big problems in converting Euler angles back and forth all the time.
- Bonta (eveonline:Dentad)
MaxPal3D
Gnoblar
Posts: 15
Joined: Tue Mar 13, 2007 12:46 pm
x 1

Post by MaxPal3D »

I have fixed my code to comply with quaternions. Thanks everybody for help. For those who came here with the same problem here is conversion code that worked for me:

Code: Select all

	vector3 OgreQuatEuler( const Ogre::Quaternion& quaternion )
			{
				Matrix3 mx2;
				quaternion.ToRotationMatrix(mx2);
				Ogre::Radian x, y, z;
				mx2.ToEulerAnglesYXZ(y, x, z);
				vector3 vect(x.valueAngleUnits(),
					y.valueAngleUnits(), z.valueAngleUnits());

				return vect;
			}

			Ogre::Quaternion EulerToOgreQuat( const vector3& degreesVector )
			{
				Matrix3 mx;
				mx.FromEulerAnglesYXZ(Degree(degreesVector.Y), Degree(degreesVector.X), Degree(degreesVector.Z));
				Quaternion result(mx);
				return result;
			}
@MaxPal3D
I suggest you use quaternions more often in your code to avoid the big problems in converting Euler angles back and forth all the time.
Yes, conforming to Ogre standards is a good advise, but there may be several cases when you need to use Euler angles. First of all this is human readability and comprehensiveness, debugging quaternions is anything but the easy task. Also Euler cannot have error value and contain only three number:) Conversions when they planned smart not to create bottlenecks are easy task and application profiler will never mention them. In my case this is also maintaining backward compatibility with the code that proved to work and runs elsewhere without Ogre.
alanic
Gnoblar
Posts: 14
Joined: Wed Dec 05, 2007 9:40 pm

Post by alanic »

MaxPal3D wrote:For those who came here with the same problem here is conversion code that worked for me:
If you don't mind me asking, what exactly did you do to fix your problem? The code you gave seems like generic Euler angles<->Quaternions conversion. Did you take other special measures in those Y>90 cases you had (which would make me think that there is indeed something wrong with Ogre's conversions), or does simple conversion like this worked for any case? If it is the latter, this would make me think that the problem was in the matrix conversions to/from that other matrix classes you used, which would leave Ogre innocent. The reason I'm asking is I'm pretty new to Ogre and you created a certain suspicion which I was planning to verify by writing a test program before I needed to use Euler angles and Quaternions.

Thanks.
MaxPal3D
Gnoblar
Posts: 15
Joined: Tue Mar 13, 2007 12:46 pm
x 1

Post by MaxPal3D »

The code you gave seems like generic Euler angles<->Quaternions conversion.
In fact it is. I am newcomer to quaternions so it wasn't obvious to me. E.g. I tried other similar looking functions like FromEulerAnglesXYZ and only later I noted that they differ in implementation and that Bontakun had mentioned certain function. Also I have tried to combine methods like obtaining quaternions like this

Code: Select all

Quaternion xRot(Degree(degreesVector.X), Vector3::UNIT_X);
Quaternion yRot(Degree(degreesVector.Y), Vector3::UNIT_Y);
Quaternion zRot(Degree(degreesVector.Z), Vector3::UNIT_Z);
Quaternion sum(xRot*yRot*zRot); 
and then matrix conversion. Also tried that snippet at the start of the thread. All of this was because I couldn't find exact pattern on wiki or forums.
Did you take other special measures in those Y>90 cases you had (which would make me think that there is indeed something wrong with Ogre's conversions), or does simple conversion like this worked for any case?
No Ogre still changes those angles as I have mentioned, I only made my code aware of this. This is not a bug because angles are still valid. The only critique possible here that you can never expect to have back pure value you have entered, but I don't know whether it is possible mathematically. I would also never doubt about Ogre code reliability, the guys behind it are really pros and they have a huge amount of beta testers :D. The only drawback of this is that some non-pros like me try to use the engine...
dreamig
Greenskin
Posts: 119
Joined: Sun Apr 08, 2012 2:42 pm

Re: Quaternions to Euler and vice versa[solved]

Post by dreamig »

hi,
i have the same probleme
but in my case i want just convert my euler angles to quaternion
is the two code

Code: Select all

Quaternion xRot(Degree(degreesVector.X), Vector3::UNIT_X);
Quaternion yRot(Degree(degreesVector.Y), Vector3::UNIT_Y);
Quaternion zRot(Degree(degreesVector.Z), Vector3::UNIT_Z);
Quaternion sum(xRot*yRot*zRot); 
and

Code: Select all

Ogre::Quaternion EulerToOgreQuat( const vector3& degreesVector )
         {
            Matrix3 mx;
            mx.FromEulerAnglesYXZ(Degree(degreesVector.Y), Degree(degreesVector.X), Degree(degreesVector.Z));
            Quaternion result(mx);
            return result;
         }
give us the same result ?
dreamig
Greenskin
Posts: 119
Joined: Sun Apr 08, 2012 2:42 pm

Re: Quaternions to Euler and vice versa[solved]

Post by dreamig »

no reply
any one did use this functions ?or somthing similair?
User avatar
Kojack
OGRE Moderator
OGRE Moderator
Posts: 7157
Joined: Sun Jan 25, 2004 7:35 am
Location: Brisbane, Australia
x 535

Re: Quaternions to Euler and vice versa[solved]

Post by Kojack »

mx.FromEulerAnglesYXZ(Degree(degreesVector.Y), Degree(degreesVector.X), Degree(degreesVector.Z));
should be the same as doing:
Quaternion sum(yRot*xRot*zRot);

The 3 letters at the end of the FromEulerAngles are the order the multiplies are performed. There's 6 versions of that function.
Order is very important, it will give different results if you do it wrong.

If the Quaternion sum(xRot*yRot*zRot) is the one you wanted, then the matching FromEulerAngles would be:
mx.FromEulerAnglesXYZ(Degree(degreesVector.X), Degree(degreesVector.Y), Degree(degreesVector.Z));
dreamig
Greenskin
Posts: 119
Joined: Sun Apr 08, 2012 2:42 pm

Re: Quaternions to Euler and vice versa[solved]

Post by dreamig »

hi again ,
stupid question
when i use this

Code: Select all

mx.FromEulerAnglesXYZ(Degree(degreesVector.X), Degree(degreesVector.Y), Degree(degreesVector.Z));
and when i must use this ,

Code: Select all

mx.FromEulerAnglesYXZ(Degree(degreesVector.Y), Degree(degreesVector.X), Degree(degreesVector.Z));
User avatar
Kojack
OGRE Moderator
OGRE Moderator
Posts: 7157
Joined: Sun Jan 25, 2004 7:35 am
Location: Brisbane, Australia
x 535

Re: Quaternions to Euler and vice versa[solved]

Post by Kojack »

You use the one that matches what you want to do or matches the coordinate system you are using. Max, Maya and other 3d software each have a default order for euler angles. Some let you set the order (I believe maya does). So if you are using euler angles from something like Maya, or a motion tracking device or something, then you need to find out what order they use and then use the matching ogre functions.
I tend to prefer YXZ order, because it works good for first person cameras. If you are looking 45 degrees up and facing north then yaw 90 degrees, you are looking 45 degrees up but facing west. If you used XYZ then you'd still be facing west, but you'd be leaning 45 degrees to the side instead of 45 degrees up.
Usually in 3d software you'd change the order (when it's possible to do that) to hide gimbal lock. Euler will always have gimbal lock, but it moves when you change order of angles. (Gimbal lock happens when the middle angle is at +/- 90 degrees. In YXZ order that's when you pitch straight up or down).

This video explains it a bit better: http://www.youtube.com/watch?v=zc8b2Jo7mno
(It's not just gimbal lock, it shows changing order of eulers too)
dreamig
Greenskin
Posts: 119
Joined: Sun Apr 08, 2012 2:42 pm

Re: Quaternions to Euler and vice versa[solved]

Post by dreamig »

i understand now ,
i made changed the coordinate system of my object to the coordinate system of ogre in another function (when i recuperate the object i made the transformation )
so i will just use

Code: Select all

mx.FromEulerAnglesXYZ(Degree(degreesVector.X), Degree(degreesVector.Y), Degree(degreesVector.Z));
because my object coordiante system are the same like ogre coordinate system
dreamig
Greenskin
Posts: 119
Joined: Sun Apr 08, 2012 2:42 pm

Re: Quaternions to Euler and vice versa[solved]

Post by dreamig »

hi again with my questions
i still do not understnad well that
my question is

Code: Select all

float angx=file[i].orient.x;
float angy=file[i].orient.y;
float angz=file[i].orient.z;
Ogre::Quaternion quat =EulerToOgreQuat( Ogre::Vector3(angx,angy,angz) );

in my case i know that the first is x angle,then y angle and the last is z angle .
in the function" EulerToOgreQuat" in this case should i use mx.FromEulerAnglesXYZ?

2- is it normal if the quaternion is negatif ?
3-is it norml when i generate quaternion when the angle are 0 (maybe x,y ,z or the three x=y=z=0)