Beauty
24-01-2012 13:17:17
Related to the properties:
Quaternion.Yaw
Quaternion.Pitch
Quaternion.Roll
SceneNode.Orientation is a Quaternion datatype. So this topic is also related to:
SceneNode.Orientation.Yaw
SceneNode.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
The Ogre related methods getYaw(), getPitch() and getRoll() return values in a different co-domain.
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:
Task
Now our task is to update our Mogre source code (in the correct way).
Ogre code from file OgreQuaternion.cpp:
Mogre code from file MogreQuaternion.cpp:
How we could do
I'm not shure how to handle the parameter.
I propose to
Quaternion.Yaw
Quaternion.Pitch
Quaternion.Roll
SceneNode.Orientation is a Quaternion datatype. So this topic is also related to:
SceneNode.Orientation.Yaw
SceneNode.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