开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 16 天
1 概述
通过前面的学习可知,矩阵与四元数在表达方位上各有优势。在不同的情况下,可以选择使用矩阵、四元数或两者的综合。
矩阵能够在坐标系之间转换向量,而四元数则不能。如果四元数需要在坐标系之间转换,则四元数需转换为矩阵。四元数能够提供平滑的线性插值,而矩阵基本上进行插值,即使插值也是非常粗糙的。因此,适当的时候矩阵与四元数的转换是非常有必要的。
2 四元数转换为矩阵
为了将角位移从四元数表示方式转换为矩阵表示方式,有必要将四元数用轴角方式描述,以方便计算:
其中,ax、ay、az表示轴的矢量,θ表示绕此轴的旋转角度。事实证明,可以方便地利用四元数的4个分量表示矩阵的9个元素。下面直接给出推导出的公式,不再逐一推导。推导需要很强的数学技巧,同时,它不是本书描述的重点,具体的推导过程可参见相关的线性代数书籍。
一般四元数转换为矩阵的公式如下:
规范化四元数转换为矩阵的公式如下:
根据上面的公式,具体实现代码如程序清单所示。
00001//四元数转换为矩阵
00002 void setRotate(const Quat& q)
00003
00004 double length2=q.length20;
00005 if(fabs(length2)<=std:numeric_limits<double>:min0)
00006 {
00007 _mat[0][0]-0.0;_mat[1][0]=0.0;_mat[2][0]-0.0;
00008 _mat[0][1]=0.0;_mat[1][1]=0.0;_mat[2][1]=0.0;
00009 _mat[0][2]=0.0;_mat[1][2]=0.0;_mat[2][2]=0.0;
00010 }
00011 else
00012 {
00013 double rlength2;
00014
00015 if(length2!-1.0)
00016 {
00017 rlength2=2.0/length2;
00018 }
00019 else
00020 {
00021 rlength2=2.0;
00022 }
00023
00024 double wx,wy,wz,xx,yy,yz,xy,xz,zz,x2,y2,z2;
00025
00026 x2=rlength2*QX;
00027 y2=rlength2*QY;
00028 22-rlength2*QZ;
00029
00030 xx=QX*x2;
00031 xy=QX*y2;
00032 xz-QX*z2;
00033
00034 yy=QY*y2;
00035 yz=QY*z2;
00036 zz=QZ*z2;
00037
00038 wx=QW*x2;
00039 wy-QW*y2;
00040 wz=QW*z2;
00041
00042 _mat[0][0]=1.0-(yy+zz);
00043 _mat[1][0]=xy-wz;
00044 _mat[2][0]=xz+wy;
00045
00046
00047 _mat[0][1]-xy+wz;
00048 _mat[1][1]=1.0-(xx+zz);
00049 _mat[2][1]-y/z-wx;
00050
00051 _mat[0][2]=xz-wy;
00052 _mat[1][2]=yz+wx;
00053 _mat[2][2]-1.0-(xx+yy);
00054}
00055
00056#if 0
00057 _mat[0][3]-0.0;
00058 _mat[1][3]=0.0;
00059 _mat[2][3]=0.0;
00060
00061 _mat[3][0]=0.0;
00062 _mat[3][1]=0.0;
00063 _mat[3][2]=0.0;
00064 _mat[3][3]-1.0;
00065 #endif
00066)}
下面对程序清单中的代码进行简单的说明。
☑ 第4行:计算四元数长度的平方。
☑ 第5行:判断四元数长度的平方的绝对值是否接近于0,如果接近,则矩阵置零。
☑ 第11~65行:按照四元数转换为矩阵的公式执行,可参照公式仔细深刻的理解。
3 矩阵转换为四元数
为了从矩阵中提取四元数,同样需要根据公式进行反推。当然,反推需要很强的数学技巧,根据前面提到的四元数转换为矩阵的公式,构建方程组,即可求解出四元数的轴角表达式。
根据前面所提到的四元数转换矩阵的公式进行反推,具体实现代码如程序清单所示。
00001//矩阵转换为四元数
00002 Quat getRotate() const
00003 {
00004 Quat q;
00005
00006 valuie_type s;
00007 value_type tq[4];
00008 int j;
00009
00010 tq[0]=1+_mat[0][0]+_mat[1][1]+_mat[2][2];
00011 tq[1]=1+_mat[0][0}-_mat[1][1}-_mat[2][2];
00012 tq[2]=1-_mat[0][0]+_mat[1][1]-_mat[2][2];
00013 tq[3]=1-_mat[0][0}-_mat[1][1]+_mat[2][2];
00014
00015 j=0;
00016 for(i=1;i<4;i++) j=(tq[i)>tq[j])?i:j;
00017
00018 if(j==0)
00019 {
00020 QW-tq[0];
00021 QX=_mat[1][2]-_mat[2][1];
00022 QY=_mat[2][0}-_mat[0][2];
00023 QZ-_mat[0][1]-_mat[1][0];
00024 }
00025 else if(j==1)
00026 {
00027 QW-_mat[1][2]-_mat[2][1];
00028 QX=tq[1];
00029 QY=_mat[0][1]+_mat[1][0];
00030 QZ-_mat[2][0]+_mat[0][2];
00031 }
00032 else if(j==2)
00033 {
00034 QW-_mat[2][0]-_mat[0][2];
00035 QX=_mat[0][1]+_mat[1][0];
00036 QY=tq[2];
00037 QZ-_mat[1][2]+_mat[2][1];
00038 }
00039 elseif(j==3)
00040 {
00041 QW=_mat[0][1}-_mat[1][0];
00042 QX-_mat[2][0]+_mat[0][2];
00043 QY=_mat[1][2]+_mat[2][1];
00044 QZ=tq[3];
00045 }
00046
00047 s=sqrt(0.25/tq[jl);
00048 QW*=s;
00049 QX*=s;
00050 QY*=s;
00051 QZ*=s;
00052
00053 return q;
00054
00055}
通过前面的介绍,相信读者已经对这些基础的数学知识有了一定的了解。
本节可能存在论述不清晰的地方,如果读者没有能够正确地理解,可以参考有关3D数学基础的书籍,里面会有非常详细、系统的讲解。