osg、漫游器、纵轴锁定原理
纵轴锁定其实就是将相机的roll、yaw、pitch三个旋转分量的roll分量消除。消除roll的方案有两种,但都是将相机的纵面(FEU)贴向目标Z,第一种是绕F轴旋转,使U轴转入FEZ面,第二种是绕U轴转,使F轴转入UEZ面,想通这两种方式有点费脑子,大家多读几遍本文能理解的。原理知道了,但是怎么计算要旋转多少呢?
下图就是osg中纵轴锁定的算法原理图:
代码注释如下:
/** The method corrects the rotation to make impression of fixed up direction.
* Technically said, it makes the roll component of the rotation equal to zero.
* rotation parameter is the rotation to be fixed.
* localUp is UP vector and must not be zero length.
* disallowFlipOver, when set on true, avoids pitch rotation component to grow
* over +/- 90 degrees. If this happens and disallowFlipOver is true,
* manipulator is rotated by 180 degrees. More precisely, roll rotation component is changed by 180 degrees,
* making pitch once again between -90..+90 degrees limits.*/
//这个方法可以修正旋转量,使得up朝向固定不变。
//具体而言就是限制旋转量的roll分量为0
//参数:rotation-将要被修正的旋转量
//参数:localUp-限定up轴向,即锁定的纵轴Z,长度不为0
//参数:disallowFlipOver-是否禁止翻转
void StandardManipulator::fixVerticalAxis( Quat& rotation, const Vec3d& localUp, bool disallowFlipOver )
{
//拆解相机局部坐标轴
Vec3d cameraUp = rotation * Vec3d( 0.,1.,0. );
Vec3d cameraRight = rotation * Vec3d( 1.,0.,0. );
Vec3d cameraForward = rotation * Vec3d( 0.,0.,-1. );
//计算R1
Vec3d newCameraRight1 = cameraForward ^ localUp;
//计算R2
Vec3d newCameraRight2 = cameraUp ^ localUp;
//叉乘后的length本质是两个向量的围成的平行四边形的面积,等价于length越大,两向量的夹角越倾向于90度,等价于旋转角度越小
Vec3d newCameraRight = (newCameraRight1.length2() > newCameraRight2.length2()) ?
newCameraRight1 : newCameraRight2;
//修正一下新右轴的方向,因为newCameraRight2可能是与原相机右轴反向的(如相机上翘朝前上方看的时候)
if( newCameraRight * cameraRight < 0. )
newCameraRight = -newCameraRight;
//计算右轴的掰正量
Quat rotationVerticalAxisCorrection;
rotationVerticalAxisCorrection.makeRotate( cameraRight, newCameraRight );
// rotate camera
rotation *= rotationVerticalAxisCorrection;//旋转修正
if( disallowFlipOver )//不允许相机"倒着看"
{
//是相机up与Z轴夹角始终小于90度
Vec3d newCameraUp = newCameraRight ^ cameraForward;
if( newCameraUp * localUp < 0. )
rotation = Quat( PI, Vec3d( 0.,0.,1. ) ) * rotation;
}
}