1、围绕一个轴旋转的Quaternion如何从几何意义上去思考
围绕轴旋转函数:FromAngleAxis( rfAngle, rkAxis );
Quaternion::IDENTITY 缺省状态下的XYZ轴信息 (X-红色,Y-绿色,Z-蓝色)![]()
Ogre::Quaternion quat;
quat.FromAngleAxis(Ogre::Radian(Ogre::Math::PI/2.0f), Ogre::Vector3(1,1,1) );
围绕轴(1,1,1)旋转90度后的情况为:
从两个图中的信息来看,每次旋转其实都是指相对于缺省的Quaternion::IDENTITY 进行的。
引申一下,对于
Ogre::Vector3中的
getRotationTo(const Vector3& dest,
const Vector3& fallbackAxis = Vector3::ZERO)
其会将从自身到dest的叉乘的向量为轴,dest到this之间的构成的角度为弧度旋转
2、四元数相乘顺序的问题,虽然有时候对四元数相乘顺序有一定了解。但是要熟练理解和掌握还有一些疑问。
我们先从一个例子来分析:
///从欧拉角计算出旋转量
GetQuaterionFromEuler( double yawRadian, double pitchRadian, double rollRadian)
{
//绕Y轴旋转量
Ogre::Quaternion yawYAxis;
yawYAxis.FromAngleAxis(Ogre::Radian(yawRadian), Ogre::Vector3::UNIT_Y);
//绕X轴旋转量
Ogre::Quaternion pitchXAxis;
pitchXAxis.FromAngleAxis(Ogre::Radian(pitchRadian), Ogre::Vector3::UNIT_X);
//绕Z轴旋转量
Ogre::Quaternion rollZAxis;
rollZAxis.FromAngleAxis(Ogre::Radian(rollRadian), Ogre::Vector3::UNIT_Z);
Ogre::Quaternion quat = yawYAxis * (pitchXAxis * rollZAxis);
}
GetQuaterionFromEuler( double yawRadian, double pitchRadian, double rollRadian)
{
//绕Y轴旋转量
Ogre::Quaternion yawYAxis;
yawYAxis.FromAngleAxis(Ogre::Radian(yawRadian), Ogre::Vector3::UNIT_Y);
//绕X轴旋转量
Ogre::Quaternion pitchXAxis;
pitchXAxis.FromAngleAxis(Ogre::Radian(pitchRadian), Ogre::Vector3::UNIT_X);
//绕Z轴旋转量
Ogre::Quaternion rollZAxis;
rollZAxis.FromAngleAxis(Ogre::Radian(rollRadian), Ogre::Vector3::UNIT_Z);
Ogre::Quaternion quat = yawYAxis * (pitchXAxis * rollZAxis);
}

上面的这个变换过程的顺序是,首先绕Y轴做方位旋转Yaw,然后绕X轴做俯仰旋转Pitch,最后绕X轴做翻滚旋转Roll。 但是在实现的时候,四元数的操作顺序是 : yawYAxis*(pitchXAxis*rollZAxis); 通过这个顺序,不从机理上进行分析的话,那么就是后进行的变换操作,需要右乘前面的四元数。
我们再简单的分析一下,如果旋转变换quad1,与旋转变换quad2;如果quad2是在相对于quad1的空间内,做的旋转变换,那么最终的旋转变换应该是 quad1*quad2; 下面有段OgreNode.cpp中一段代码,从这段代码我们也可以了解四元数的旋转顺序关系。
enum TransformSpace
{
/// Transform is relative to the local space
TS_LOCAL,
/// Transform is relative to the space of the parent node
TS_PARENT,
/// Transform is relative to world space
TS_WORLD
};
void Node::rotate( const Quaternion &q, TransformSpace relativeTo)
{
// Normalise quaternion to avoid drift
Quaternion qnorm = q;
qnorm.normalise();
switch(relativeTo)
{
case TS_PARENT:
// Rotations are normally relative to local axes, transform up
mOrientation = qnorm * mOrientation;
break;
case TS_WORLD:
// Rotations are normally relative to local axes, transform up
mOrientation = mOrientation * _getDerivedOrientation().Inverse()
* qnorm * _getDerivedOrientation();
break;
case TS_LOCAL:
// Note the order of the mult, i.e. q comes after
mOrientation = mOrientation * qnorm;
break;
}
needUpdate();
}
{
/// Transform is relative to the local space
TS_LOCAL,
/// Transform is relative to the space of the parent node
TS_PARENT,
/// Transform is relative to world space
TS_WORLD
};
void Node::rotate( const Quaternion &q, TransformSpace relativeTo)
{
// Normalise quaternion to avoid drift
Quaternion qnorm = q;
qnorm.normalise();
switch(relativeTo)
{
case TS_PARENT:
// Rotations are normally relative to local axes, transform up
mOrientation = qnorm * mOrientation;
break;
case TS_WORLD:
// Rotations are normally relative to local axes, transform up
mOrientation = mOrientation * _getDerivedOrientation().Inverse()
* qnorm * _getDerivedOrientation();
break;
case TS_LOCAL:
// Note the order of the mult, i.e. q comes after
mOrientation = mOrientation * qnorm;
break;
}
needUpdate();
}