正文

绕给定轴的旋转插值2010-06-04 17:08:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/yuqiexing/51296.html

分享到:

有些时候希望从一个向量A绕一给定轴旋转到另一个向量B,并对其进行插值(比如动画)。如果给定轴恰好为AB平面的法向量,则以其为旋转轴可以直接构建四元数,取旋转角度步长为1°或者更小即可。最大旋转角为AB向量之间的夹角。当步长累积超过最大旋转角时,停止插值。但是当给定轴是其他时,最大旋转角为多大呢?

 

 

如图所示,P为给定轴,现在要对AP旋转到B进行插值。实际上这个问题可以看做是PA平面绕P旋转到PB平面的问题。设PA法向量为N1PB法向量为N2。因此最大旋转角为N1N2的夹角(两个平面的夹角)。

 

 

 

示例代码如下:

 

// vCur为当前旋转向量(in/out)dRotateStep为旋转步长,vAxis为给定轴,vOri为起始向量(A),vTar为终止向量(B

 

  BOOL InpByQuaternion(Vertex3d& vCur,double dRotateStep,Vertex3d& vAxis,Vertex3d& vOri,Vertex3d& vTar)

{

       Vertex3d vTempCur = vCur;

       vTempCur.Normailize();

 

       Vertex3d vTempNormalOri = vAxis ^ vOri;              // 计算N1

       Vertex3d vTempNormalTar = vAxis ^ vTar;   // 计算N2

     Vertex3d vTempNormalCur = vAxis ^ vTempCur; // 计算当前N

 

       double dRotateAlpha = ALineWithLine(vTempNormalOri,vTempNormalCur);

       // 计算最大旋转角

       double dMaxAlpha = ALineWithLine(vTempNormalOri,vTempNormalTar);

 

       if((dRotateAlpha - dMaxAlpha) > -1e-6)

              return FALSE;

 

       double dTempAlpha = dRotateAlpha + dRotateStep;

 

       double dLength = vCur.Length();

       double dStep = dRotateStep;

       if(dTempAlpha < dMaxAlpha)

              dStep = dRotateStep;

       else

              dStep = dMaxAlpha - dRotateAlpha;

 

       Vertex3d vNewAxis = vTempNormalOri ^ vTempNormalTar;

       vNewAxis.Normailize();

       Quaternion qq(dStep,vNewAxis);

       vTempCur = qq * vCur;

 

       vTempCur.Normailize();

       vTempCur *= dLength;

       vCur = vTempCur;

       return TRUE;

}

 

下面是一些辅助小函数

 double ALineWithLine(Vertex3d& vVec1,Vertex3d& vVec2)
 {
  return vVec1.GetCrossAcuteAngle(vVec2);
 }

 

double Vertex3d::GetCrossAcuteAngle(const Vertex3d& rhv) const
{
 double dCosAngle = GetCrossAcuteAngleCos(rhv);
 double Angle;

 // 计算注意,考虑到acos函数只能计算-1到1之间,因此对于1和-1分开处理
 if(fabs(dCosAngle - 1) < MathEx::TOL)
  Angle = 0;
 else if(fabs(dCosAngle + 1) < MathEx::TOL)
  Angle = MathEx::ONE_PI;
 else
  Angle = acos( dCosAngle );
 return Angle;
}

 

double Vertex3d::GetCrossAcuteAngleCos(const Vertex3d& rhv) const
{
 double ddd = Length() * rhv.Length();
 if(fabs(ddd) < MathEx::TOL)
  return 1; // 0向量与任意向量平行,其夹角可以认为是0°,cos值为1
 return fabs(((*this) * rhv)) / ddd;

阅读(3150) | 评论(2)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册