第120讲 矩阵

 

矩阵在三维变换中扮演着重要角色。比如三维物体的旋转,又或者是平移缩放等,这些操作都是有矩阵来决定的。
 

上一讲里面我们说了向量,所以这一讲我们来简单的说说矩阵,关于矩阵的定义以及他的一些属性这里就不做细说,我们主要说他和我们接下来的三维编程相关的一些东西,以便大家在接触到三维图形的时候心里有数。


 

世界变换矩阵,在绘制物体的通常都是按照自己的坐标系进行绘制,那么绘制完成后想要在频幕上显示出来这时需要使用同一的坐标系,而这个坐标系就是世界坐标系。而从物体从自己的坐标系中变换到世界坐标系中的变换矩阵就是世界变换矩阵。
 

那么世界变换矩阵包括旋转矩阵,平移矩阵,缩放矩阵。
 


 

为什么矩阵可以用来旋转平移缩放物体呢?好吧,看下面:
 

假设点P(x,y,z,1):


 

矩阵:M =
 

 

{ m00,m01,m02,m03,
 

 

 

m10,m11,m12,m14,
 

 

 

m20,m21,m22,m23,
 

 

 

m30,m31,m32,m33 }
 

如果M的m00,m11,m22,m33都为1,而其他的都是0的话那么M被称为单位矩阵。


 

那么,点P经矩阵M变换后他的位置在哪里呢?


 

向量和矩阵相乘大家一定都清楚了,那么我们现在来描述一下他们的物理意义。还记得上一讲里面我们所说的向量和向量相加的物理意义吗?其实这里我们可以看成是几个向量的和,所以P点的物理位置被改变了。那么向量和矩阵相乘怎么能够看成是几个向量的和呢?好吧,这里解释一下,对于矩阵M来说,其实我们可以看成是由四个向量组成的,其中:
 

V1 ={mm00,m01,m02,m03 };


 

V2 ={m10,m11,m12,m13 };


 

V3 ={m20,m21,m22,m23 }'
 

V4 ={m30,m31,m32,m33 };


 

而这四个向量分别乘以一个不同的常数,然后相加就得到了变换的结果,那么这四个常数哪里来的呢?当时就是点P的四个分量啦。所以,我们可以这么来理解:


 

P*M = x*V1 + y*V2 + z*V3 + 1*V4;


 

我们可以推导验证一下:


 

P*M ={x*m00 + y*m10 + z*m20 + 1*m30,x*m01 + y*m11 + z*m21 + 1*m31,x*m02 + y*m12 + z*m22 + 1*m32,m03+m13+m23+m33 };


 

上面的结果和下面的结果对比一下是不是一样的呢?


 

那么现在结果是不是出来了呢?如果M是单位矩阵,那么点P的位置没有变动。


 

如果M不是单位矩阵就会改变点 P的位置,但是通常情况下我们的变换矩阵其实都是单位矩阵的基础上修改几个变值就得到我们所想要的矩阵了。所以从上面的变换式中我们不难看出,其实对角线的m00,m11,m22他们的作用就是缩放,而m30,m31,m32的作用就是平移。当变换矩阵中这些位置上的数值都不为0时那么该矩阵具有缩放也有平移。


 

关于旋转矩阵,这里不做推导,不过给出来大家有兴趣的就推导一下,没有兴趣的就了解一下:
 

关于X轴旋转的旋转绝阵据,angle表示角度。
 

 

 

{ 1, 0,  

 

 

 

0, 

 

0 }
 

Rx 

 

 

{ 0,cos(angle), 

 

sin(angle), 

0 }
 

 

 

{ 0, -sin(angle), 

cos(angle), 

0 }
 

 

 

{ 0, 0, 

 

 

 

 

 

 

 

 

 

 

 

, 1 }



 

关于Y轴的旋转矩阵:


 

 

 

{ cos(angle), 

0, 

-sin(angle),0 }
 

Ry 

 

 

{ 0, 

 

1, 

 

0, 

 

 

0 }
 

 

 

{ sin(angle), 

 

0, 

 

cos(angle), 

0 }
 

 

 

{ 0, 0, 

 

 

 

 

 

 

 

 

 

 

 

 

1 }


 

关于Z轴的旋转矩阵:


 

 

 

{ cos(angle), 

sin(angle), 

0, 0 }
 

Ry 

 

 

{ -sin(angle), cos(angle), 

 

0, 

0 }
 

 

 

{ 0, 

 

 

 

0, 

 

 

 

 

 

 

 

1, 

0 }
 

 

 

{ 0,  

 

0, 

 

 

 

 

 

0, 

1 }


 

这几个矩阵的推导过程并不复杂,有兴趣的话可以尝试。因为关于这些变换矩阵XNA数学库提供的有相关操作。
 


 

在XNA数学库中矩阵定义如下:
 

typedef struct _XMMATRIX{
 

 

union
 

 

{
 

 

 

XMVECTOR[4];

// 这里是四个向量__m128数组
 

 

 

struct{
 

 

 

 

FLOAT _11,_12,_13,_14;


 

 

 

 

FLOAT _21,_22,_23,_24;


 

 

 

 

FLOAT _31,_32,_33,_34;


 

 

 

 

FLOAT _41,_42,_43,_44;


 

 

 

}
 

 

 

FLOAT m[4][4];


 

 

}
 

} XMMATRIX


 

XNA的XMMATRIX针对C++重载了常用的操作符,比如,* ,*= 等等
 


 

XNA对矩阵的操作:


 

XMMATRIX XMMatrixIdentity();

//获取一个单位矩阵


 

XMVECTOR XMMatrixDeterminant(XMMATRIX);

// 求一个矩阵的行列式


 

XMMATRIX XMMatrixTranspose(XMMATRIX);

//求一个矩阵的转置矩阵


 

XMMATRIX XMMatrixInverse(XMVECTOR,XMMATRIX);

//求矩阵的逆矩阵
 


 

XMECTOR XMVector2Transform(XMVECTOR,XMMATRIX);

// 向量矩阵相乘


 

………………


 

拥有大量的操作函数,这里就不一一例举,这几个都是常用的。
 


 

那么XMMATRIX的优势是什么?当然是速度快了,但是也必然有他的劣势,那就是一不小心你的程序就崩溃了,当然这不是你的事,只能说是不小心,因为XMMATRIX的运行使用了硬件加速所以对内存对齐有需求,而从我们看到的__m128类型就应该不难发现,这是需要16位对齐的,然后在X86系统上堆默认是按照8为对齐,所以如果你打算将XMMATRIX作为类的数据成员时那就得小心小心再小心些。XMMATRIX通常不要将他所谓数据成员储存,而是作为局部变量或者全局变量来使用,那么我们该使用什么来储存矩阵信息呢?
 

答案是XMLOAT4X4,他不要求内存对齐,但是可以很方便的和XMMATRIX相互转换,也就是说当我们需要矩阵相乘的时候将XMFLOAT4X4转换为XMMATRIX再使用XMMatrixMultiply对矩阵进行相乘,然后再转换到XMFLOAT4X4对象中,当然不用担心这些转换会带来效率的损失,这些些函数库都是XNA库 提供的,速度相当快。


 

那么如果我们一定要在数据成员中使用XMMATRIX怎么办呢?第一是使用_aligned_malloc(sizeof(T), 16);

进行分配空间然后再在该空间上创建包含有XMMATRIX的对象。第二重新改写new操作,然后按照16位字节对齐分配内存,当然这两种方式其实都一样的啦,就是在分配内存的时候一定要保证是16字节对齐的。


 

关于XMFLOAT4X4和XMMATRIX的转换函数如下:


 

XMStoreFloat4x4(XMFLOAT4X4&

dest,XMMATRIX source);

// 将矩阵数据储存进XMFLOAT4X4的数据中
 

XMMATRIX XMLoadFloat4x4(XMFLOAT4X4 data);

// 将XMFLOAT4X4数据加载进XMMATRIX中


 

其他的3X3,3X4,4X3等等类型都是一样的操作。


 

ok,那么关于矩阵我们就简单的说了这些,接下来我们就准备进去DirectX11吧,不过最近在外面出差,真没时间更新,实在抱歉。


//==================================
 

 

回复D查看目录,回复数字查看相应章节

原文始发于微信公众号(

C/C++的编程教室

):第120讲 矩阵

|

发表评论