3D图形:矩阵与线性变换

前言
由于OpenGLES的进度再度搁浅,所以准备从再次学习3D图形的深层次的知识,这一篇主要讲的是如何使用矩阵表示旋转、缩放、投影、镜像、切变,这些线性变换将会由浅入深,也算是为了后面的仿射变换做铺垫吧!接下来,我们一一看这些线性变换.
旋转
日常开发过程中旋转是一种很常见的图形变换,现在我们就对2D环境下和3D环境下的图像变换进行讲解说明.
2D环境下的旋转
假设现在物体现在就在原点位置,例如下图.

然后物体旋转角度为θ = 3/π,在旋转当中经常被认为逆时针为正方向,顺时针为负方向,那么对于基向量p,q是怎么变化的呢?如下图所示.这里我直接用绘图工具了,图片粗糙请见谅.

我们从图片中可以看到旋转后的新向量p1,q1的值(当然了,实际上是根据三角函数计计算出来的),然后通过这两个值我们就可以构造出如下通用旋转矩阵.通过下面的矩阵,我们是不是很熟悉呢?有没有仿射变换的赶脚.不要着急,我们慢慢看.

</b>
3D环境下的旋转
在3D的环境下,我们讨论的不再是绕点旋转,而是绕轴旋转.虽然是绕轴旋转,我们也要定义出正负方向来.在左右坐标系中的情况是有所不同的,什么?不知道左右坐标系如何定义的?那么看下图所示.

那么在我们的坐标系中如何判断出正负方向呢?比如我们在左手坐标系中需要使用的左手法则俩判断正负方向,而在右手坐标系中则正好相反.我们就拿在左手左边系为例,法则示意图如下所示.(左右手法则不过多解释,如果不懂请自行查看高中物理相关知识)

|左手坐标系|
|:---:|:---:|:--:|
|从哪里看|正方向|负方向|
|从轴的负端点向正端点看|逆时针|顺时针|
|从轴的正端点向负端点看|顺时针|逆时针|
上面我们了解完旋转方向了,接下来我们先看看三种特殊情况,分别绕x,y,z轴进行旋转.
我们还是来看基向量的变化,首先对于3D中的基向量p ,q ,r由于是绕x轴进行旋转的,所以说基向量p是没有任何变化的,变化的只有q ,r两个基向量,假设旋转的角度θ = 3/π,那么如下图所示.

然后如果在2D中通过三角函数公式,我们可以获得以下的旋转变换矩阵.

那么绕y,z轴与之类似,我就不做图了,直接上公式了.


那么上面看完了三种特殊的旋转方式,接下来,我们就看一下在3D中绕任意轴旋转的情况.
如图所示,如果向量v(粉色)绕轴向量n旋转得到向量v'(粉色),我们直接如果直接观察的话是非常困难的.

但是如果我们把向量v和向量v'进行分解,然后把旋转的θ放在一个平面中来解决问题,这样,我们的旋转问题就转化为简单的2D问题了.如下图所示.

这里我要对各个向量做一下解释说明,
其中n为v在旋转轴上的投影 (假设旋转轴为n',那么n=n'(v·n'));
v为旋转之前的向量;
v'为旋转之后的向量 ;
p为v垂直于n的分量(p'同理);
ω为同时垂直于n和p的向量,长度与p相等.
上面基本我们把所有的向量解释了,现在已经知道的条件是向量v和旋转轴n'以及旋转角度θ要计算的是向量v'.(怎么跟计算题似的😂)
整体的思路是这样的,我们可以使用向量n和向量p'表示向量v',v' = n +p';然后n=n'(v·n')以及p'=ωsinθ+ncosθ,这三个向量表示公式来进行表示分解.计算过程如下.(说明:由于时间原因,本人就直接用纸写了计算过程了.骚栋的字是夏练三伏 冬练三九,终究还是败了)
首先我们先对p'=ωsinθ+pcosθ进行解析,步骤如下
p'=ωsinθ+pcosθ
代换p和ω
p = v - n = v - ( v·n')n'
ω = n' x p = n' x (v - n) = n' x v - n' x n = n' x v - 0 = n' x v
**p'=ωsinθ+pcosθ = (n' x v)sinθ +(v - ( v·n')n')cosθ **

上面我们已经计算出p'然后带入v' = n +p',计算如下所示
v' = (n' x v)sinθ +(v - ( v·n')n')cosθ +n'(v·n')
现在我们既然有了转换关系,那么我们就要对三个基向量p ,q ,r进项转换了,我们就拿其中p = [1,0,0]来举例说明.其中旋转轴向量n' = [nx ,ny,nz],那么经过旋转之后的基向量p'是什么情况呢?步骤如下所示.

同样的对于基向量q = [0,1,0] ,r = [0,0,1],我们使用公式v' = (n' x v)sinθ +(v - ( v·n')n')cosθ +n'(v·n')一样求出他们转换之后的基向量.具体的过程我就不在重复了,如果向量计算记不清楚的可以查看3D图形:向量的相关计算,计算结果如下.


结果上面的重重计算,我们终于得到了绕任意轴n = [nx ,ny,nz],的旋转矩阵.
如下图所示.

</br>
缩放
相比于旋转而言,缩放比较简单,(缩放的定义我就不过度的解释了),我们就从2D的环境和3D环境以及沿着任意方向缩放三个方面来看缩放这个知识点.
2D的环境和3D环境沿着坐标轴缩放

如果沿着坐标轴进行缩放,那么每一个坐标轴都有缩放因子,所以2D环境下有两个缩放因子Kx和Ky,那么基向量p和q根据缩放因子的影响,我们可以得到下面结论.

然后根据变换,我们就可以得到在2D环境下的缩放矩阵.如下所示.

那么,通过2D环境下的缩放矩阵,我们可以得到3D环境下的缩放矩阵.

</br>
沿着任意方向缩放
上面我们把在2D的环境和3D环境的缩放情况说明了一下,接下来我们看一下沿着任意方向缩放的情况,如图所示.(假设在向量n方向上的缩放因子为k)
在图中n为缩放方向,v为缩放之前的向量,v'为缩放之后的向量,a和a'分别为v和v'垂直于缩放方向的分量,b和b'分别为v和v'在缩放方向上的投影.

思路是这样的,
首先v只是在n的方向上进行了缩放,所以缩放前后a是没有任何改变的,也就是说,a = a';
b和b'分别为v和v'在缩放方向上的投影,所以会有b = (v·n)n和b' = (v'·n)n;
然后,再就是通过向量的加减法,我们可以得知,v = a +b和v' = a' +b';
上面是三个具体的条件,我们根据条件用n,v,k来表示v'.具体的计算过程如下.
b' = kb = k(v·n)n
a' = a = v - b = v - (v·n)n
v' = a' + b' = v - (v·n)n + k(v·n)n = v +(k-1)(v·n)n
上面我们已经得到了v' 的表达式,然后我们就需要对各个基向量进行计算了,这里使用的是基向量p = [1,0],具体的计算过程如下所示.

同理,基向量 q与之类似,结果如下所示.

那么,在2D中的缩放矩阵如下所示.

3D因为原理一样就不在推导了,在3D中的缩放矩阵结果如下所示.

</br>
正交投影
一般来说呢,投影就意味着降维操作.这篇博客主要研究的是正交投影.透视投影将在后面的博客中体现,但是我还是要那两张图片给来说明一下正交投影和透视投影的不同.简单点说正交投影原来的点和投影点的直线相互平行,但是透视投影所有的投影线会相交于一点.如下所示.


接下来我们就直接看看2D和3D环境下的正交投影矩阵.





</b>
当然了我们也是可以向任意直线或者平面投影,直线或者平面必须通过原点的.然后我们利用缩放的结果,有如下的结果.


</br>
镜像
镜像是一种变换,其作用就是按照直线或者平面"翻折".如图所示.

镜像和投影都是可以通过缩放矩阵进行变换的,我们只需要把缩放矩阵的缩放因子设置为-1即可,那么在2D和3D情况下的沿着任意轴的镜像矩阵如下所示.


</br>
切变
切变是一种坐标系"扭曲"变换,非均匀的拉伸它,切变的时候角度会发生改变,但是面积(2D)或者是体积(3D)不会发生改变.

具体的解释意义如下所示.

那么在3D环境下的是切变的形式又是如何的呢?如下所示.

当然了,其实切变并不常用.😄
</br>
结束语
经过两三天的写作,整理学习,总算是写完了旋转、缩放、投影、镜像、切变的线性变换,学习3D图形更多的是需要一个本子和一支笔,只有不断的演算才能真正的掌握这些.如果你喜欢骚栋,请继续关注,下一篇我将对矩阵的其他知识以及齐次矩阵的相关知识做研究整理.
最后还是要附上<<3D数学基础 图形与游戏开发>>的pdf版的传送门来结束线性变换的相关知识.