绕任意轴旋转.docx
《绕任意轴旋转.docx》由会员分享,可在线阅读,更多相关《绕任意轴旋转.docx(13页珍藏版)》请在冰豆网上搜索。
绕任意轴旋转
几何变换详解
在三维图形学中,几何变换大致分为三种,平移变换(Translation),缩放变换(Scaling),旋转变换(Rotation)。
以下讨论皆针对DirectX,所以使用左手坐标系。
平移变换
将三维空间中的一个点[x,y,z,1]移动到另外一个点[x',y',z',1],三个坐标轴的移动分量分别为dx=Tx,dy=Ty,dz=Tz,即
x'=x+Tx
y'=y+Ty
z'=z+Tz
平移变换的矩阵如下。
缩放变换
将模型放大或者缩小,本质也是对模型上每个顶点进行放大和缩小(顶点坐标值变大或变小),假设变换前的点是[x,y,z,1],变换后的点是[x',y',z',1],那么
x'=x*Sx
y'=y*Sy
z'=z*Sz
缩放变换的矩阵如下。
旋转变换
这是三种变换中最复杂的变换,这里只讨论最简单的情况,绕坐标轴旋转,关于绕任意轴旋转,在后续的随笔中介绍。
绕X轴旋转
绕X轴旋转时,顶点的x坐标不发生变化,y坐标和z坐标绕X轴旋转θ度,旋转的正方向为顺时针方向(沿着旋转轴负方向向原点看)。
[x,y,z,1]表示变换前的点,[x',y',z',1]表示变换后的点。
变换矩阵如下。
关于旋转的正方向,OpenGL与多数图形学书籍规定旋转正方向为逆时针方向(沿着坐标轴负方向向原点看),比如ComputerGraphicsCVersion,p409。
绕Y轴旋转
绕Y轴旋转时,顶点的y坐标不发生变化,x坐标和z坐标绕Y轴旋转θ度。
[x,y,z,1]表示变换前的点,[x',y',z',1]表示变换后的点。
变换矩阵如下。
绕Z轴旋转
绕Z轴旋转时,顶点的z坐标不发生变化,x坐标和y坐标绕Z轴旋转θ度。
[x,y,z,1]表示变换前的点,[x',y',z',1]表示变换后的点。
变换矩阵如下。
绕坐标轴旋转的矩阵推导
上面三个旋转矩阵是如何得来的呢?
我们推导一下,首先看一下二维的情况,再扩展到三维即可。
实际上上面三种绕坐标轴旋转的情况属于特殊的二维旋转,比如绕Z轴旋转,相当于在与XOY平面上绕原点做二维旋转。
假设点P(x,y)是平面直角坐标系内一点,其到原点的距离为r,其与X轴的夹角为A,现将点P绕原点旋转θ度,得到点P'(x',y'),P'与X轴的夹角为B,则A=B-θ。
(注意,在二维坐标中,逆时针旋转时角度为正,顺时针旋转时角度为负,下图中由P旋转到P',角度为θ,若是由P'转到P,则角度为-θ)。
于是可得下面的转换方程
(式一)
写成矩阵的形式就是
求得旋转矩阵为
由于这里使用齐次坐标,所以还需加上一维,最终变成如下形式
绕Z轴旋转矩阵
和前面给出的绕Z轴旋转矩阵完全吻合。
对于绕X轴旋转的情况,我们只需将式一中的x用y替换,y用z替换,z用x替换即可。
替换后得到
(式二)
对应的旋转矩阵为
绕X轴旋转矩阵
对于绕Y轴旋转的情况,只需对式二做一次同样的替换即可,的到的变换方程为
对应的变换矩阵为
绕Y轴旋转矩阵
逆矩阵
平移变换矩阵的逆矩阵与原来的平移量相同,但是方向相反。
旋转变换矩阵的逆矩阵与原来的旋转轴相同但是角度相反。
缩放变换的逆矩阵正好和原来的效果相反,如果原来是放大,则逆矩阵是缩小,如果原来是缩小,则逆矩阵是放大。
==HappyCoding==
作者:
zdd
出处:
绕任意轴旋转
绕任意轴旋转的情况比较复杂,主要分为两种情况,一种是平行于坐标轴的,一种是不平行于坐标轴的,对于平行于坐标轴的,我们首先将旋转轴平移至与坐标轴重合,然后进行旋转,最后再平移回去。
∙将旋转轴平移至与坐标轴重合,对应平移操作
∙旋转,对应操作
∙步骤1的逆过程,对应操作
整个过程就是
对于不平行于坐标轴的,可按如下方法处理。
(该方法实际上涵盖了上面的情况)
1将旋转轴平移至原点
2将旋转轴旋转至YOZ平面
3将旋转轴旋转至于Z轴重合
4绕Z轴旋转θ度
5执行步骤3的逆过程
6执行步骤2的逆过程
7执行步骤1的逆过程
假设用v1(a1,b2,c2)和v2(a2,b2,c2)来表示旋转轴,θ表示旋转角度。
为了方便推导,暂时使用右手系并使用列向量,待得出矩阵后转置一下即可,上面步骤对应的流程图如下。
步骤1是一个平移操作,将v1v2平移至原点,对应的矩阵为
步骤2是一个旋转操作,将p(p=v2-v1)旋转至XOZ平面,步骤3也是一个旋转操作,将p旋转至与Z轴重合,这两个操作对应的图如下。
做点p在平面YOZ上的投影点q。
再过q做Z轴垂线,则r是p绕X轴旋转所得,且旋转角度为α,且
于是旋转矩阵为
现在将r绕Y轴旋转至与Z轴重合,旋转的角度为-beta(方向为顺时针),且
于是得到旋转矩阵为
最后是绕Z轴旋转,对应的矩阵如下
如果旋转轴是过原点的,那么第一步和最后一步的平移操作可以省略,也就是把中间五个矩阵连乘起来,再转置一下,得到下面的绕任意轴旋转的矩阵
即
对应的函数代码如下。
voidRotateArbitraryAxis(D3DXMATRIX*pOut,D3DXVECTOR3*axis,floattheta)
{
D3DXVec3Normalize(axis,axis);
floatu=axis->x;
floatv=axis->y;
floatw=axis->z;
pOut->m[0][0]=cosf(theta)+(u*u)*(1-cosf(theta));
pOut->m[0][1]=u*v*(1-cosf(theta))+w*sinf(theta);
pOut->m[0][2]=u*w*(1-cosf(theta))-v*sinf(theta);
pOut->m[0][3]=0;
pOut->m[1][0]=u*v*(1-cosf(theta))-w*sinf(theta);
pOut->m[1][1]=cosf(theta)+v*v*(1-cosf(theta));
pOut->m[1][2]=w*v*(1-cosf(theta))+u*sinf(theta);
pOut->m[1][3]=0;
pOut->m[2][0]=u*w*(1-cosf(theta))+v*sinf(theta);
pOut->m[2][1]=v*w*(1-cosf(theta))-u*sinf(theta);
pOut->m[2][2]=cosf(theta)+w*w*(1-cosf(theta));
pOut->m[2][3]=0;
pOut->m[3][0]=0;
pOut->m[3][1]=0;
pOut->m[3][2]=0;
pOut->m[3][3]=1;
如果旋转轴是不过原点的,那么第一步和最后一步就不能省略,将所有七个矩阵连乘起来,得到如下变换矩阵
对应如下这个超长的矩阵,在这里(u,v,w)=(a2,b2,c2)-(a1,b1,c1),且是单位向量,a,b,c分别表示(a1,b1,c1)
将上面的过程写成函数,该函数接受四个参数,第一个参数是一个输出参数,用来保存得到的旋转矩阵,第二个和第三个参数是旋转轴的两个端点,最后一个参数是旋转角度θ,注意,在函数中我们已经将上面的矩阵转置了,因为上面是按照列向量计算的。
voidRotateArbitraryLine(D3DXMATRIX*pOut,D3DXVECTOR3*v1,D3DXVECTOR3*v2,floattheta)
{
floata=v1->x;
floatb=v1->y;
floatc=v1->z;
D3DXVECTOR3p=*v2-*v1;
D3DXVec3Normalize(&p,&p);
floatu=p.x;
floatv=p.y;
floatw=p.z;
floatuu=u*u;
floatuv=u*v;
floatuw=u*w;
floatvv=v*v;
floatvw=v*w;
floatww=w*w;
floatau=a*u;
floatav=a*v;
floataw=a*w;
floatbu=b*u;
floatbv=b*v;
floatbw=b*w;
floatcu=c*u;
floatcv=c*v;
floatcw=c*w;
floatcostheta=cosf(theta);
floatsintheta=sinf(theta);
pOut->m[0][0]=uu+(vv+ww)*costheta;
pOut->m[0][1]=uv*(1-costheta)+w*sintheta;
pOut->m[0][2]=uw*(1-costheta)-v*sintheta;
pOut->m[0][3]=0;
pOut->m[1][0]=uv*(1-costheta)-w*sintheta;
pOut->m[1][1]=vv+(uu+ww)*costheta;
pOut->m[1][2]=vw*(1-costheta)+u*sintheta;
pOut->m[1][3]=0;
pOut->m[2][0]=uw*(1-costheta)+v*sintheta;
pOut->m[2][1]=vw*(1-costheta)-u*sintheta;
pOut->m[2][2]=ww+(uu+vv)*costheta;
pOut->m[2][3]=0;
pOut->m[3][0]=(a*(vv+ww)-u*(bv+cw))*(1-costheta)+(bw-cv)*sintheta;
pOut->m[3][1]=(b*(uu+ww)-v*(au+cw))*(1-costheta)+(cu-aw)*sintheta;
pOut->m[3][2]=(c*(uu+vv)-w*(au+bv))*(1-costheta)+(av-bu)*sintheta;
pOut->m[3][3]=1;
}