第一部分 矩阵
约定:
- 向量使用列向量表示。(而非行向量)
- 变换矩阵作用于向量。(而非作用于坐标轴)
一、基本概念
矩阵是m×n个标量组成的二维数组。矩阵非常便于表示线性变换例如平移旋转缩放。
二、矩阵乘法
两个矩阵相乘:
矩阵乘法又称为串接(concatenation)。
如果AB都是变换矩阵,则P=AB也是变换矩阵,等同于进行A、B两者的变换。
此特性可以把一连串变换预先计算为单一矩阵,再用该矩阵高效变换大批向量。
- 仅当两个矩阵的内维(inner dimension)相等才可相乘。
- 矩阵乘法不符合交换律,即乘法的次序会影响结果。
列向量和行向量乘以矩阵:
列向量乘矩阵,矩阵必须位于向量左方。
行向量乘矩阵,矩阵必须位于向量右方。(矩阵是转置的)
三、单位矩阵
单位矩阵通常写作I,单位矩阵是正方形矩阵,对角线上的元素全为1,其他元素为0。
单位矩阵乘以任何矩阵都为得到和原来一样的矩阵。
四、 逆矩阵
矩阵A的逆矩阵$A^{-1}$能用于还原矩阵A的变换。
- 矩阵乘以他的逆矩阵结果是单位矩阵。
- 矩阵串接后求逆,等于反向串接各个矩阵的逆矩阵。$(ABC)^{-1} = C^{-1}B^{-1}A^{-1}$
- 并非所有矩阵都有逆矩阵,然而所有仿射矩阵都有逆矩阵。
五、转置矩阵
矩阵A的转置(transpose)矩阵$A^{T}$就是把原来矩阵以主对角线(diagonal)为对称轴翻转。即行变成列。
- 标准正交矩阵(纯旋转)的逆矩阵等于转置矩阵。(此特性很有用,计算转置比求逆矩阵快得多)
- 有的数学库使用列向量,有的使用行向量,二者的矩阵是转置关系。
- 矩阵串接的转置,等于反向串接各个矩阵。(和逆矩阵一样)
补充:叉积表示为矩阵
$\left[ \begin{matrix} 0 & -z_a & y_a \ z_a & 0 & -x_a \ -y_z & x_a & 0 \end{matrix} \right]$ * $\left[ \begin{matrix} x_b \ y_b \ z_b \end{matrix} \right]$ = result
第二部分 矩阵变换
一、齐次坐标
问题:
已知2x2矩阵可以表示二维旋转,同理3x3矩阵可以表示三维旋转。但是平移不属于线性变换,不能用矩阵乘法表示。
解决方法:
但是如果使用4x4矩阵,把平移坐标放在单位矩阵的末列,然后给要变换的点(即位置向量)引入新坐标w(值为1)延申为四维坐标,然后乘以该4x4矩阵,则可以实现平移变换。该四维坐标即齐次坐标(Homogeneous coordinates)。
处理方向向量与处理点(位置向量)不同,需要忽略平移变换。所以位置向量的w分量为1,而方向向量的w分量为0,方向向量乘以变换矩阵后可以消去平移信息。
齐次坐标转换为非齐次坐标:
四维齐次坐标转换为三维坐标的方法是:把x、y、z分量除以w分量。
点除以w不影响点的坐标,但是方向除以w会产生无穷大。即三维空间的纯方向在四维齐次空间其实是无穷远的点。
二、基础变换矩阵
平移:
$M_{translate} =
\left[ \begin{matrix}
1 & 0 & 0 & tx
0 & 1 & 0 & ty
0 & 0 & 1 & tz
0 & 0 & 0 & 1
\end{matrix} \right]$
缩放:
$M_{scale} =
\left[ \begin{matrix}
Sx & 0 & 0 & 0
0 & Sy & 0 & 0
0 & 0 & Sz & 0
0 & 0 & 0 & 1
\end{matrix} \right]$
旋转:
$M_{rotateX} =
\left[ \begin{matrix}
1 & 0 & 0 & 0
0 & cosθ & -sinθ & 0
0 & sinθ & cosθ & 0
0 & 0 & 0 & 1
\end{matrix} \right]$
$M_{rotateY} =
\left[ \begin{matrix}
cosθ & 0 & sinθ & 0
0 & 1 & 0 & 0
-sinθ & 0 & cosθ & 0
0 & 0 & 0 & 1
\end{matrix} \right]$
$M_{rotateX} =
\left[ \begin{matrix}
cosθ & -sinθ & 0 & 0
sinθ & cosθ & 0 & 0
0 & 0 & 1 & 0
0 & 0 & 0 & 1
\end{matrix} \right]$
以上旋转矩阵对于左手坐标系而言左手螺旋方向为正方向、对于右手坐标系而言右手螺旋为正方向。即正旋是转轴指向摄像机时( x -> y ) ( y -> z ) ( z -> x )的旋转方向。
绕y轴旋转的旋转矩阵相对其他两个是转置的,因为从z到x是绕回去。
三、坐标空间和基变换
计算机图形学中,把物体的位置、定向及缩放转换到另一个坐标系中,称为基变换。
坐标空间的层次结构:
坐标系是相对的,所以坐标空间有层次结构。每个坐标空间都是某个坐标空间的子空间。除了最顶层的坐标空间没有父空间,称为世界空间。
构建改变基的矩阵:
把店或者矢量从任何子坐标系变换至父坐标系的矩阵写作$M_{c -> p}$,可以用父空间坐标表示的子空间基向量来构建:
$M_{c -> p} =
\left[ \begin{matrix}
| & | & | & |
x_c & y_c & z_c & t_c
| & | & | & |
0 & 0 & 0 & 1
\end{matrix} \right]$
$x_c$为子空间x轴的单位基向量在父空间的坐标表示。
$y_c$为子空间y轴的单位基向量在父空间的坐标表示。
$z_c$为子空间z轴的单位基向量在父空间的坐标表示。
$t_c$为子坐标系相对父坐标系的位移。
推导过程:
- 父空间坐标来表示子空间的一点:
$A_p = O_c + ax_c + by_c + cz_c$
$ A_p = (x_{O_c}, y_{O_C}, z_{O_c}) + a(x_{x_c}, y_{x_c}, z_{x_c}) + b(x_{y_c}, y_{y_c}, z_{y_c}) + c(x_{z_c}, y_{z_c}, z_{z_c})$
注:父坐标表示的子空间基向量$x_c$、$y_c$、$z_c$。
注:父坐标表示的子空间原点$O_c$。
注:子空间点(a,b,c)在父坐标的表示为$A_p$。
- 矩阵乘向量形式:
$A_p = (x_{O_c}, y_{O_C}, z_{O_c})+
\left[
\begin{matrix}
x_{x_c} & x_{y_c} & x_{z_c}
y_{x_c} & y_{y_c} & y_{z_c}
z_{x_c} & z_{y_c} & z_{z_c}
\end{matrix}
\right]
\left[
\begin{matrix}
a
b
c
\end{matrix}
\right]
$
- 即:
$A_p = (x_{O_c}, y_{O_C}, z_{O_c})+
\left[
\begin{matrix}
| & | & |
x_c & y_c & z_c
| & | & |
\end{matrix}
\right]
\left[
\begin{matrix}
a
b
c
\end{matrix}
\right]
$
- 引入齐次坐标:
$A_p =
\left[
\begin{matrix}
| & | & | & |
x_c & y_c & z_c & t_c
| & | & | & |
0 & 0 & 0 & 1
\end{matrix}
\right]
\left[
\begin{matrix}
a
b
c
1
\end{matrix}
\right]
$
关于缩放:
三个坐标轴不一定是单位矢量,缩放单位基矢量即可缩放子坐标系统。子空间缩放n倍,那么基矢量$x_c$、$y_c$、$z_c$的长度为n。
关于变换法线:
法线有个要求即与屏幕垂直。需要使用逆转置矩阵来变换。
已知基变换矩阵反求基矢量:
由于基变换矩阵是由三个子空间基矢量和平移组成的,所以对于任何4x4仿射矩阵都可以直接从指定列获取基矢量。
正交矩阵的逆矩阵等于转置矩阵,所以对于正交变换矩阵不仅可以求出子空间坐标轴在父空间的表示(即每一列)。也能很快求出父空间坐标轴在子空间的表示(即每一行)。
内存中存储矩阵:
- 按列矢量连续存储。
优点是要取得4个矢量中的一个,直接返回四个连续的矢量数值。
- 列矢量在内存中分散对齐。
优点是SIMD运算更快。
四、MVP矩阵
模型空间(ModelSpace):
模型空间也称为物体空间。
规范:模型空间原点一般在物体中心或者人物的脚与地面之间,坐标轴方向一般是合乎直觉的方向。
世界空间(WorldSpace):
此空间把所有单个物体联系在一起。是最上层的父空间。
从模型空间到世界空间的矩阵即M矩阵$M_{Model}$。
规范:通常置于接近可玩游戏空间的中心。因为当xyz坐标值过大时,会出现明显的浮点小数误差。
观察空间(ViewSpace):
观察空间(ViewSpace)又称为摄像机空间。
从世界空间到观察空间的矩阵即V矩阵$M_{View}$。
左手坐标系中+z代表深度。在右手坐标系(如opengl)中-z代表深度。
Unity引擎虽然模型和世界空间都是左手坐标系,但是Unity的观察空间和OpenGL一样为右手坐标系,即摄像机指向-z轴,需要对z轴取反。(Mview = Mnegz·Mview)
Unity左右手坐标系的转换对脚本编程影响不大,但是调用Camera.cameraToWorldMatrix时要注意坐标系。
裁剪空间(ClipSpace)
裁剪空间又称为齐次裁剪空间,裁剪空间的目标是方便对平截头体外面的图元进行裁剪/剔除。
平截头体由6个裁剪面组成,决定了摄像机能看到的空间。
从观察空间到裁剪空间的矩阵即P矩阵$M_{Perspective}$。而P矩阵分为正交投影矩阵和透视投影矩阵。
A. 透视投影
$M_{perspective} =
\left[
\begin{matrix}
M & 0 & 0 & 0
0 & N & 0 & 0
0 & 0 & A & B
0 & 0 & C & 0
\end{matrix}
\right]
$
-
REW: 不同的情况下推导的透视投影矩阵不同:
左手坐标系和右手坐标系(+z深度或-z深度/far和near的正负)会影响投影矩阵。(通常影响C项)
规范化z坐标的方式会影响投影矩阵。(通常影响AB项)
视场角FOV和长宽比aspect会影响投影矩阵。(通常影响MN项) -
顶点裁剪判断:
-w < x < w
-w < y < w
-w < z < w -
示例:Unity引擎的透视投影矩阵:
$M_{perspective} =
\left[
\begin{matrix}
{{cot (fov / 2)} \over aspect} & 0 & 0 & 0
0 & {cot(fov / 2)} & 0 & 0
0 & 0 & -{{Far + Near} \over {Far - Near}} & -{{2NearFar} \over {Far - Near}}
0 & 0 & -1 & 0
\end{matrix}
\right]
$
注:Unity引擎观察空间为右手坐标系,变换后的裁剪空间为左手坐标系。
注:Unity透视矩阵变换后的z分量在[-w,w]之间。而在DX中为[0,w]之间,透视投影矩阵是不同的。
注:Unity透视矩阵变换后的点w分量为-z。
B. 正交投影
- 示例:Unity引擎的正交投影矩阵:
$M_{ortho} =
\left[
\begin{matrix}
{1 \over aspect · size} & 0 & 0 & 0
0 & {1 \over size} & 0 & 0
0 & 0 & -{2 \over {Far - Near}} & -{{Far + Near} \over {Far - Near}}
0 & 0 & 0 & 1
\end{matrix}
\right]
$
注:Unity正交投影矩阵变换后的点w分量依然为1。
注:Unity正交投影变换后frustum已经变成了立方体。
屏幕空间(ViewSpace):
屏幕空间是二维的。在裁剪空间完成裁剪操作后,需要投影到二维的屏幕空间,得到实际的二维屏幕坐标。
- 第一步:齐次除法
即用w分量除以xyz分量,得到归一化设备坐标(NDC)。Unity/OpenGL的NDC中xyz都是[-1, 1]范围,DX的NDC中z分量范围[0, 1]。
- 第二步:映射到屏幕
$screenX = x · {pixelWidth \over 2} + {pixelWidth \over 2}$
$screenY = y · {pixelHeight \over 2} + {pixelHeight \over 2}$
z坐标通常被用于深度缓存。
w坐标也会保留用于其他作用。
Unity引擎的屏幕坐标原点在左下角。OpenGL中原点也在屏幕左下角。