1.数学分析上一篇中间在做旋转的时候我直接用了旋转变换矩阵,当时觉得很尴尬,因为之前没说过是怎么产生的该矩阵。1)矩阵和向量的微妙关系如果您还记得向量加法的几何意义,那么不难看懂下
1. 数学分析
上一篇中间在做旋转的时候我直接用了旋转变换矩阵,当时觉得很尴尬,因为之前没说过是怎么产生的该矩阵。
1) 矩阵和向量的微妙关系
如果您还记得向量加法的几何意义,那么不难看懂下面的等式:
[x] [x] [0] [0] [1] [0] [0]
v = [y] = [0] + [y] + [0] = x * [0] + y * [1] + z * [0]
[z] [0] [0] [z] [0] [0] [1]
我们可以看到一个向量或者说是一个点,可以表示为该向量的各分量与某坐标轴单位向量的乘积之和。
我们设p,q,r分别代表这三个单位向量,则可以转化为这种形式:
v = xp + yq + zr
现在我们把p,q,r一般化,令p = [px py pz], q = [qx qy qz], r = [rx ry rz],我们把它们组成一个矩阵
[ px py pz ]
M = [ qx qy qz ]
[ rx ry rz ]
然后用向量[x y z]乘以该矩阵,得
[x y z] × M = [(x*px +y*qx + z*rx) (x*py + y*qy + z*ry) (x*pz + y*qz + z*rz)] = xp + yq + zr
呵呵,看到M的作用了吗,他把向量[x y z]执行了一次矩阵变换,变成了v。这就是变换矩阵的来源。那他可以做什么呢?下面就是重点了。
我们用坐标轴的单位向量(我们管他叫基向量)来分别乘以M:
[1 0 0] × M = p
[0 1 0] × M = q
[0 0 1] × M = r
哈哈,这个性质太重要了:对于一个坐标轴(上面的[1 0 0] [0 1 0] [0 0 1]都是某个坐标轴的单位向量),我们可以使用一个向量来变换他。比如对于X轴,我们只要给出一个变换向量p,就可以把X轴按p向量进行变换。而且我们可以同时给出p,q,r,同时对X,Y,Z三个轴进行变换。
下面的图非常形象的表示了我们现在可以如何利用这个性质:
我们可以把图中的绿色、红色箭头看作是坐标轴的单位向量,分别对应X轴[1 0]和Y轴[0 1],那么我们对他们进行变换会发生什么?
比如,我们把X轴从向量[1 0]变换到[2 1],把Y轴从[0 1]变换到[-1 2],那么效果如下图:
进行了这个变换,我们发现,空姐的照片不仅被放大了一些,而且还绕Z轴旋转了一些。这就是刚才我们构建的矩阵
M = [ 2 1 ] 的作用
[-1 2 ]
现在弄清楚变换矩阵和向量的关系了吧,我们可以构建矩阵M,用M的第一行来变换物体坐标系的X轴向量,用M的第二行来变换物体坐标系的Y轴向量,用M的第三行来变换物体的Z轴向量,就好象控制3ds max的操作柄一样。现在我们可以来推导旋转矩阵了。
2) 3D旋转变换矩阵的推导。
我们首先还用一个俯视图来推导,我们顺着Z轴俯视下来,现在让物体绕Z轴旋转,那么物体的X轴控制柄向量和Y轴控制柄向量应该如何变换呢?看图:
因为是绕Z轴旋转,那么X轴和Y轴都应该旋转同一个角度,设为theta。那么对于X轴单位向量(1,0),则旋转theta后,坐标变为 cos(theta), sin(theta)。Y轴单位向量(0,1)在旋转theta后,坐标变为-sin(theta),cos(theta)。那么我们开始整理矩阵:
对于X控制柄,变换向量为:[cos(theta) sin(theta) 0]
对于Y控制柄,变换向量为:[-sin(theta) cos(theta) 0]
对于Z控制柄,变换向量为: [ 0 0 1] (因为Z控制柄没有变化,扔为Z轴单位向量)
好了,我们已经求得了某点绕Z轴旋转的变换矩阵了:
M =
[ cos(theta) sin(theta) 0 ]
[ -sin(theta) cos(theta) 0 ]
[ 0 0 1 ]
2. 代码实现
根据上面的推导,我们可以同理推出绕X,Y轴的变换矩阵,下面的函数是实现一个综合旋转,可以获得让一个点,绕X,Y,Z同时转的变换矩阵:
void _CPPYIN_3DLib::BuildRotateMatrix(double anglex_du, double angley_du, double anglez_du, MATRIX4X4_PTR m) // 创建同时绕X,Y,Z旋转不同度数的变换矩阵
{
// 初始化针对绕X,Y,Z轴旋转的3个变换矩阵,将他们都复制为单位矩阵,如果绕某轴不旋转,则单位矩阵不会影响结果
MATRIX4X4 mx, my, mz;
memcpy((void *)(&mx), (void *)&MATRIXI_4X4, sizeof(MATRIX4X4));
memcpy((void *)(&my), (void *)&MATRIXI_4X4, sizeof(MATRIX4X4));
memcpy((void *)(&mz), (void *)&MATRIXI_4X4, sizeof(MATRIX4X4));
double sin_theta, cos_theta; // 缓存计算结果,减少CPU开销
if (anglex_du > EPSILON)
{
cos_theta = FastCos(anglex_du);
sin_theta = FastSin(anglex_du);
MatrixCreate(&mx,
1, 0, 0, 0,
0, cos_theta, sin_theta, 0,
0, -sin_theta, cos_theta, 0,
0, 0, 0, 1);
}
if (angley_du > EPSILON)
{
cos_theta = FastCos(angley_du);
sin_theta = FastSin(angley_du);
MatrixCreate(&my,
cos_theta, 0, -sin_theta, 0,
0, 1, 0, 0,
sin_theta, 0, cos_theta, 0,
0, 0, 0, 1);
}
if (anglez_du > EPSILON)
{
cos_theta = FastCos(anglez_du);
sin_theta = FastSin(anglez_du);
MatrixCreate(&mz,
cos_theta, sin_theta, 0, 0,
-sin_theta, cos_theta, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1);
}
// 变换矩阵相乘,获得最终变换矩阵
MATRIX4X4 mtemp;
MatrixMul(&mx, &my, &mtemp);
MatrixMul(&mtemp, &mz, m);
}
使用这个函数,对上篇文章的某些函数做了简化,不用每次都手写这些矩阵了,这次的DEMO对上次的金字塔同时执行X和Z轴的变换。
请注意我修改了世界变换与旋转物体的顺序,并且保存旋转后的点的存储位置也不一样了哦。
截图:
3. 代码下载
完整项目源代码下载:>>点击进入下载页<<
4. 补充内容
其实这次只说了旋转矩阵的推导,但通过这个过程,我们知道了向量和矩阵之间的微妙关系,对于其他变换,如:缩放、投影、镜像、切变也都可以利用这种关系来推导出来,这里就不多费口舌了。
一个比较特殊的情况是平移。如果您仔细看了文章就会发现,对X,Y,Z三个坐标轴进行变换并不能达到使物体平移的目的,这也就是为什么要用4D向量来表示和变换了,具体这第4维怎么用,有空我们再研究研究4D齐次坐标的原理吧,有兴趣的朋友可以发链接分享哦。
对于本次来客串的空姐,纯属增加趣味,所有的肖像权、发行权、出版权全归您所有,如果您认为权利被侵犯了,我会立刻更换图片~~
转自:http://blog.csdn.net/cppyin/archive/2011/02/18/6193076.aspx