《Unity3D C#数学系列之矩阵基础》中我们说到一个4×4的矩阵可以用来对三维空间中的点或向量进行各种变换,包括平移、旋转、缩放(当然还有错切、镜像等,由于我工作中这几种从来没用过,所以这里就不说这两种变换了)以及这几种变化的组合。这些变换有一个统一的名字,叫做仿射变换。三维空间中,只要是仿射变换,就可以用一个4×4的变换矩阵来表示。
但是为什么变换矩阵一定是4×4的呢,3×3行不行?答案是不行。如果不考虑点的平移,只考虑向量或点的旋转、缩放,3×3的矩阵就可以了。但如果考虑点的平移,3×3的矩阵就不满足要求了,必须扩充到4×4。至于为什么3×3无法表示平移,下面我们推导平移矩阵的时候就知道答案了。
我们知道三维空间中,一个点或者向量用3个变量x,y,z来表示就行了,但是在进行矩阵变换的时候,需要增加一维变量w。用(x, y, z, w)表示的向量或点,就叫齐次坐标。向量的w分量为0,点的w分量为1(为0时可以忽略掉平移的效果,如向量平移后还是它本身,为1时会保留平移的效果)。
设4×4的变换矩阵为 M \textbf{M} M4×4。
设一个点A变换前的坐标为(x,y,z,w),变换后的点A’ 坐标为(x’,y’, z’,w’),则有
(还记得为什么点或向量的坐标要写成列矩阵的的形式吗,不记得了去看看上一篇文章)
矩阵乘法展开后就有方程组
我们上面说过,点的齐次坐标的w分量为1,所以又有
从上面方程组中的最后一个方程我们可以看出(无论x、y、z为何值都满足这个方程), m \textbf{m} m41、 m \textbf{m} m42、 m \textbf{m} m43全部等于0, m \textbf{m} m44等于1。
然后,我们令A(x,y,z,1)分别为(1, 0, 0, 1),(0,1,0, 1),(0,0,1, 1)同时我们需要分析出对应变换后的坐标A’(x’,y’, z’,1),然后代入上面的方程组的前3个,一般就能推导出平移、旋转、缩放的矩阵了。
设点A(x,y,z,1)平移(a,b,c,0)(即在x轴方向平移a个单位,y方向平移b个单位,z方向平移c个单位),则A’点的坐标为(x + a,y + b,z + c,1),代入上面的方程组中有
无论x、y、z为何值都满足上面方程组中的各个方程,必然有
所以平移的变换矩阵为
平移矩阵的逆矩阵如下:
如果我们用一个3×3的矩阵来进行平移变换,将方程组展开,会发现根本没有解。所以3×3的矩阵无法表示平移,但4×4的矩阵可以。其根本原因是因为平移不是线性变换,必须要扩展一维才可以。
设向量(x,y,z,0)沿坐标轴缩放(kx,ky,kz,0),则缩放后的坐标为(kxx,kyb,kzz,0),代入2.1中的方程组中有
显然有
所以沿坐标轴缩放(kx,ky,kz)的缩放矩阵为
其逆矩阵为如下:
设向量 v ⃗ \vec{v} v(x,y,z,0)沿单位向量 n ⃗ \vec{n} n(nx,ny,nz,0)缩放k个单位,假设缩放后的坐标为 v ′ ⃗ \vec{v'} v′(nx,ny,nz,0),现在我们要求缩放矩阵,必须先把 v ′ ⃗ \vec{v'} v′给求出来。
我们将 v ⃗ \vec{v} v分为两个部分,一个是 v ⃗ \vec{v} v⊥,其垂直于 n ⃗ \vec{n} n,沿着 n ⃗ \vec{n} n缩放将对其不产生任何影响;另一个是 v ⃗ \vec{v} v//,其平行于 n ⃗ \vec{n} n,沿着 n ⃗ \vec{n} n缩放将对其产生影响。
由于 v ⃗ \vec{v} v//平行于 n ⃗ \vec{n} n,则有 v ⃗ \vec{v} v// = ( v ⃗ \vec{v} v· n ⃗ \vec{n} n) n ⃗ \vec{n} n。
所以 v ⃗ \vec{v} v//沿着 n ⃗ \vec{n} n缩放k个单位后的值为k( v ⃗ \vec{v} v· n ⃗ \vec{n} n) n ⃗ \vec{n} n。
又由于 v ⃗ \vec{v} v⊥ ⃗垂直于 n ⃗ \vec{n} n,所以 v ⃗ \vec{v} v⊥ ⃗沿着 n ⃗ \vec{n} n缩放k个单位后的值仍为 v ⃗ \vec{v} v⊥ = v ⃗ \vec{v} v- v ⃗ \vec{v} v// = v ⃗ \vec{v} v-( v ⃗ \vec{v} v· n ⃗ \vec{n} n) n ⃗ \vec{n} n。
于是
将 v ⃗ \vec{v} v=(x,y,z), n ⃗ \vec{n} n=(nx,ny,nz )代入有,
代入2.1中的方程组中有
于是
所以沿单位向量 n ⃗ \vec{n} n(nx,ny,nz)缩放k个单位的缩放矩阵为
在推导旋转矩阵之前,我们先看看不同坐标系之间的变换矩阵是怎么推导的,这是推导旋转矩阵的基础。
我们在说一个点或者一个向量的坐标的时候,一定要知道这个坐标是在什么坐标系下的。
我们在说一个点或者一个向量的坐标的时候,一定要知道这个坐标是在什么坐标系下的。
我们在说一个点或者一个向量的坐标的时候,一定要知道这个坐标是在什么坐标系下的。
只要说到坐标,一定要立马想到这个坐标所在的坐标系。
同一个点或者同一个向量,在不同坐标系下,它们的坐标值是不一样的。所以我们这里才会来求不同坐标系之间的变换矩阵。
这里先直接给出结论:
具体推导过程如下。
我们在上一篇文章《Unity3D C#数学系列之矩阵基础》中说过逆矩阵可以用来还原某种变换或者说反变换,且正交矩阵的逆矩阵就是其转置矩阵。并且,由标准正交基(长度为1的坐标系的x、y、z轴向量)构成的矩阵其实就是正交矩阵。
而对于向量,无论怎么平移,向量的值都是不变的,所以对于向量其变换矩阵使用3×3就足够了。那么对于向量,坐标系O’x’y’z’到Oxyz的变换矩阵也可求到了,如下。
我们先来看二维平面上的旋转。在二维平面上,我们说的旋转是指绕着某一个点旋转。
说一条线绕着某一点(假设名字为旋转中心)旋转,是指该线上的所有点绕着旋转中心旋转。
说一个多边形绕着某一点(假设名字为旋转中心)旋转,是指这个多边形上的每一个点绕着旋转中心旋转。
我们先来推导下二维平面Oxyz坐标系中,绕原点O旋转的旋转矩阵。
设坐标系Oxyz是左手坐标系(因为Unity中世界坐标系和局部坐标系都是左手坐标系,所以我们这里举例子也按照Unity的来),A点绕着原点O旋转了θ度到达新点A‘,求旋转矩阵。
推导过程如下。
旋转矩阵是正交矩阵。
(还记得正交矩阵满足什么条件吗?忘记了去复习一下《Unity3D C#数学系列之矩阵基础》第4.4节)
所以其逆矩阵就是其转置矩阵。
如图,左手坐标系Oxyz中,B点在Oxyz坐标系的坐标为(a, b),求A点绕点B旋转θ角的旋转矩阵。
其推导过程如下:
三维空间说的旋转是指一个点或者一个向量绕着某一个方向或者说某一个轴旋转(二维是绕着某一个点)。
如图,A点绕X轴旋转θ度后到达A‘点(我们这里还是假设Oxyz坐标系是左手坐标系的)。
绕着X轴旋转其实可以理解在Oyz这个二维平面内绕着原点O进行旋转。然后将A’点和A点的x轴坐标设置为一样的。
上面这句话可能没表达清楚,看下面这张图应该就能理解了,其中灰色平面与Oyz平面平行。
根据上一节我们讲的二维平面中绕原点的旋转矩阵,咱们可以直接写出三维空间中绕x轴的旋转矩阵。
同绕x轴的旋转,绕着y轴的旋转可以理解为在Oxz这个二维平面内绕着原点O进行旋转。然后将A’点和A点的y轴坐标设置为一样的。
绕y轴旋转θ角的旋转矩阵为
同绕x轴的旋转,绕着z轴的旋转可以理解为在Oxy这个二维平面内绕着原点O进行旋转。然后将A’点和A点的z轴坐标设置为一样的。
绕z轴旋转θ角的旋转矩阵为
如图,Oxyz坐标系中,A点绕向量 r ⃗ {\vec{r}} r =(a,b,c)旋转θ度到达A’点,求旋转矩阵。
绕任意轴的旋转与二维平面的旋转推导方法类似的,关键在建立一个辅助坐标系。
其推导过程如下:
后面我实在是不想算了,要用的时候直接查资料吧。。。
博主本文博客链接。