Beauty

24-01-2012 13:17:17

Related to the properties:

SceneNode.Orientation is a Quaternion datatype. So this topic is also related to:

Many months ago I recognized, that the Yaw/Pitch/Roll properties of Mogre Quaternions return strage values.

If you have the problem that

In the Mogre source code the bug

Just for information.

Different results for Mogre and Ogre

This topic I created related to the co-domain of the returned values of Yaw, Pitch and Roll.

In most cases, the user would like to have a Yaw co-domain of -180 .. +180.

Additionally

Related to this behaviour I had a discussion in the topic co-domains of Quaternion::getYaw(), getPitch() and getRoll().

There I got an answer for the reason:

Why Mogre returns different Euler Angle values:

Task

Now our task is to update our Mogre source code (in the correct way).

How we could do

I'm not shure how to handle the parameter.

I propose to

**Quaternion.Yaw**

Quaternion.Pitch

Quaternion.RollQuaternion.Pitch

Quaternion.Roll

SceneNode.Orientation is a Quaternion datatype. So this topic is also related to:

**SceneNode.Orientation.Yaw**

SceneNode.Orientation.Pitch

SceneNode.Orientation.RollSceneNode.Orientation.Pitch

SceneNode.Orientation.Roll

Many months ago I recognized, that the Yaw/Pitch/Roll properties of Mogre Quaternions return strage values.

If you have the problem that

**Pitch returns NaN**values (undefined), look to the topic Euler angles - current bugs + improved Euler Angle Class.In the Mogre source code the bug

**is fixed now**, but there will be "unfixed" binary files in the world for a longer time.Just for information.

Different results for Mogre and Ogre

This topic I created related to the co-domain of the returned values of Yaw, Pitch and Roll.

**Co-domain**: Currently Mogre returns Euler values in the range`Yaw -90 .. 90`

Pitch -180 .. 180

Roll -180 .. 180

**The Ogre related methods getYaw(), getPitch() and getRoll() return values in a different co-domain.**`Yaw -180 .. 180`

Pitch ?? .. ??

Roll ?? .. ??

In most cases, the user would like to have a Yaw co-domain of -180 .. +180.

Additionally

**we want to have the same behaviour for Mogre and Ogre**.Related to this behaviour I had a discussion in the topic co-domains of Quaternion::getYaw(), getPitch() and getRoll().

There I got an answer for the reason:

Why Mogre returns different Euler Angle values:

Ogre's getYaw code is:

`if (reprojectAxis)`

{

// yaw = atan2(localz.x, localz.z)

// pick parts of zAxis() implementation that we need

Real fTx = 2.0f*x;

Real fTy = 2.0f*y;

Real fTz = 2.0f*z;

Real fTwy = fTy*w;

Real fTxx = fTx*x;

Real fTxz = fTz*x;

Real fTyy = fTy*y;

// Vector3(fTxz+fTwy, fTyz-fTwx, 1.0-(fTxx+fTyy));

return Radian(Math::ATan2(fTxz+fTwy, 1.0f-(fTxx+fTyy)));

}

else

{

// internal version

return Radian(Math::ASin(-2*(x*z - w*y)));

}

The reprojectAxis bool defaults to true.

This means that by default ogre is doing a different calculation than mogre, which is probably why I'm getting the full range while you are getting a smaller value. I'd probably get the 60,180,180 thing if I used the non default formula.

Task

Now our task is to update our Mogre source code (in the correct way).

**Ogre code**from file*OgreQuaternion.cpp*:

Radian Quaternion::getRoll(bool reprojectAxis) const

{

if (reprojectAxis)

{

// roll = atan2(localx.y, localx.x)

// pick parts of xAxis() implementation that we need

// Real fTx = 2.0*x;

Real fTy = 2.0f*y;

Real fTz = 2.0f*z;

Real fTwz = fTz*w;

Real fTxy = fTy*x;

Real fTyy = fTy*y;

Real fTzz = fTz*z;

// Vector3(1.0-(fTyy+fTzz), fTxy+fTwz, fTxz-fTwy);

return Radian(Math::ATan2(fTxy+fTwz, 1.0f-(fTyy+fTzz)));

}

else

{

return Radian(Math::ATan2(2*(x*y + w*z), w*w + x*x - y*y - z*z));

}

}

//-----------------------------------------------------------------------

Radian Quaternion::getPitch(bool reprojectAxis) const

{

if (reprojectAxis)

{

// pitch = atan2(localy.z, localy.y)

// pick parts of yAxis() implementation that we need

Real fTx = 2.0f*x;

Real fTy = 2.0f*y;

Real fTz = 2.0f*z;

Real fTwx = fTx*w;

Real fTxx = fTx*x;

Real fTyz = fTz*y;

Real fTzz = fTz*z;

// Vector3(fTxy-fTwz, 1.0-(fTxx+fTzz), fTyz+fTwx);

return Radian(Math::ATan2(fTyz+fTwx, 1.0f-(fTxx+fTzz)));

}

else

{

// internal version

return Radian(Math::ATan2(2*(y*z + w*x), w*w - x*x - y*y + z*z));

}

}

//-----------------------------------------------------------------------

Radian Quaternion::getYaw(bool reprojectAxis) const

{

if (reprojectAxis)

{

// yaw = atan2(localz.x, localz.z)

// pick parts of zAxis() implementation that we need

Real fTx = 2.0f*x;

Real fTy = 2.0f*y;

Real fTz = 2.0f*z;

Real fTwy = fTy*w;

Real fTxx = fTx*x;

Real fTxz = fTz*x;

Real fTyy = fTy*y;

// Vector3(fTxz+fTwy, fTyz-fTwx, 1.0-(fTxx+fTyy));

return Radian(Math::ATan2(fTxz+fTwy, 1.0f-(fTxx+fTyy)));

}

else

{

// internal version

return Radian(Math::ASin(-2*(x*z - w*y)));

}

}

**Mogre code**from file*MogreQuaternion.cpp*:

Radian Quaternion::Roll::get()

{

return Radian(Math::ATan2(2*(x*y + w*z), w*w + x*x - y*y - z*z));

}

//-----------------------------------------------------------------------

Radian Quaternion::Pitch::get()

{

return Radian(Math::ATan2(2*(y*z + w*x), w*w - x*x - y*y + z*z));

}

//-----------------------------------------------------------------------

Radian Quaternion::Yaw::get()

{

return Radian(Mogre::Math::ASin(-2*(x*z - w*y)));

}

How we could do

I'm not shure how to handle the parameter.

I propose to

- Keep the properties Yaw/Pitch/Roll[/*:m]

- Add the Ogre code as additional methods (instead of put them into the properties)

. . . . . private or public?

. . . . . I think private as long as we don't know when we need false for*reprojectAxis*.

. . . . . To keep it private would avoid confusions for users.[/*:m]

- Call that methods from the Properties[/*:m][/list:u]

For "internal usage" the parameter*reprojectAxis*is false.

I don't know the background and which "internal" methods call getYaw() / getPitch() / getRoll().

Perhaps there are also other parts of the math related classes, which should be updated.

Pure .NET classes

Just for information:

About 20 classes are not wrapped, because of a better performance. Instead they will be compiled for .NET (as C++ code).

The downside is, that we need to update them manually, although I think that changes are very rare.

All "custom" classes are listed in the wiki (here).

In the source code you find them here:

`Mogre\Main\include\Custom\ // header files`

Mogre\Main\src\Custom\ // source files