正文

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

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

分享到:

有些时候希望从一个向量A绕一给定轴旋转到另一个向量B,并对其进行插值(比如动画)。如果给定轴恰好为AB平面的法向量,则以其为旋转轴可以直接构建四元数,取旋转角度步长为1°或者更小即可。最大旋转角为AB向量之间的夹角。当步长累积超过最大旋转角时,停止插值。但是当给定轴是其他时,最大旋转角为多大呢?     如图所示,P为给定轴,现在要对A绕P旋转到B进行插值。实际上这个问题可以看做是PA平面绕P旋转到PB平面的问题。设PA法向量为N1,PB法向量为N2。因此最大旋转角为N1和N2的夹角(两个平面的夹角)。       示例代码如下:   // 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; } 

阅读(5127) | 评论(2)


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

评论

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