【UnityShader_Ojors的脚印】在Shader之前_基础数学

在本篇开始前,先向大家推荐一本书:《3D数学基础:图形与游戏开发》
这本书很多游戏相关的数学知识都讲得很细,值得一看。以前学的东西好多都还给老师了,啃这本书,补回了以前的好多知识啊!(本人数学渣,看这本书费了点时间,还好之前学过,能懂在讲什么。。。)

本文章面向的对象是有3D数学基础但是由于长时间没接触变生疏,或对某些知识点理解尚有问题的人群。


坐标系

首先要讲的是坐标系,在3D中,坐标系类型有很多,比较重要的是3D坐标系,常见的分两种:左手坐标系和右手坐标系,主要区别是Z轴的方向(我们定义X轴默认正方向为右,Y轴默认正方向为上),左手系Z轴正方向为指向屏幕内部,右手系Z轴正方向为指向屏幕外部:

【UnityShader_Ojors的脚印】在Shader之前_基础数学_第1张图片
左手系 (图截自《3D数学基础:图形与游戏开发》)
【UnityShader_Ojors的脚印】在Shader之前_基础数学_第2张图片
右手系 (图截自《3D数学基础:图形与游戏开发》)

Ps:在Unity中,默认使用的是左手坐标系(摄像机的观察空间(以摄像机为原点的坐标系)除外)。

在一个空间中,有了坐标系的存在,就可以确定空间中物体的具体位置。

向量

向量首先要跟标量区分:向量具有方向和大小等概念,而标量只有大小。在Unity中常用的向量有法线、切线等。

在表示形式上,向量可以用一个一维数组表示,比如:
![][1]
[1]:http://latex.codecogs.com/png.latex?a=\begin{bmatrix}1&2&3\end{bmatrix}

![][2]
[2]:http://latex.codecogs.com/png.latex?a=\begin{bmatrix}1\2\3\end{bmatrix}
横向书写的称为行向量,竖向书写的称为列向量,向量中的每一个分量对应于其n维空间中的分量,上例中分量为x、y、z,至于在使用时是用行还是列,要根据实际情况来确定。(后面会提到)
而在物理中,向量具有其实际意义:比如上述的a向量,表示由一个点到另外一个点位移,上式中,表示点A向x方向移动1个单位,y方向移动2个单位,z方向移动3个单位到达点B。(注意,在坐标系中,位移没有具体的位置,可以在任意位置表示,只表示位移量和方向)

向量运算

向量大小:向量的大小也称为向量的模,表示位移量的大小,以3维向量为例:
![][1]
[1]:http://latex.codecogs.com/png.latex?a=\begin{bmatrix}1&2&3\end{bmatrix}
该向量的大小计算为:
![][3]
[3]:http://latex.codecogs.com/png.latex?\left|a\right|=\sqrt{12+22+3^2}
即为两点间的距离公式
在Shader中,我们经常要将向量标准化(也称为归一化),也就是把向量的大小置为1,在坐标系中可以理解为以一个点为圆(球)心,半径为1的一个圆(球)
标准化公式如下:
![][4]
[4]:http://latex.codecogs.com/png.latex?a_{normal}=\frac{a}{\left|a\right|}

【UnityShader_Ojors的脚印】在Shader之前_基础数学_第3张图片
单位圆 (图截自《3D数学基础:图形与游戏开发》)

向量运算

向量的运算很简单,其实就是各个分类的相加减。
以加法为例(减法相同):
![][5]
[5]:http://latex.codecogs.com/png.latex?\begin{bmatrix}1\2\3\end{bmatrix}+\begin{bmatrix}3\2\1\end{bmatrix}=\begin{bmatrix}1+3\2+2\3+1\end{bmatrix}=\begin{bmatrix}4\4\4\end{bmatrix}

向量运算几何意义:

a+b:a的起点到b的终点的向量;
c-d:d的终点到c的终点的向量;


【UnityShader_Ojors的脚印】在Shader之前_基础数学_第4张图片
向量加减 (图截自《3D数学基础:图形与游戏开发》)

向量点乘

点乘形式:
![][6]
[6]:http://latex.codecogs.com/png.latex?\begin{bmatrix}a_1\a_2\a_3\end{bmatrix}.\begin{bmatrix}b_1\b_2\b_3\end{bmatrix}=a_1b_1+a_2b_2+a_3b_3
几何点乘公式:
![][7]
[7]:http://latex.codecogs.com/png.latex?a\cdot{b}=\left|a\right|*\left|b\right|\ast\cos\theta
其几何意义为向量a在向量b上的投影(当夹角大于90°时结果为负值)

【UnityShader_Ojors的脚印】在Shader之前_基础数学_第5张图片
点乘 (图截自《3D数学基础:图形与游戏开发》)

向量点乘结果为一个标量。

向量叉乘

叉乘形式:
(其实就是,除当前行外的另外两行组成2*2矩阵,主对角线的乘积减去副对角线的乘积)
![][9]
[9]:http://latex.codecogs.com/png.latex?\begin{bmatrix}x_1\y_1\z_1\end{bmatrix}\times\begin{bmatrix}x_2\y_2\z_2\end{bmatrix}=\begin{bmatrix}y_1z_2-z_1y_2\z_1x_2-x_1z_2\x_1y_2-y_1x_2\end{bmatrix}
几何叉乘:
向量叉乘结果为垂直于两向量所在平面的向量,叉乘结果向量的方向由两个,取决于坐标系为左手坐标系还是右手坐标系。
方向分辨方法为(a x b为例):
左手系:通过左手法则判断,四指由a向量收向b向量,拇指方向即为结果向量方向。
右手系:通过右手法则判断,四指由a向量收向b向量,拇指方向即为结果向量方向。

【UnityShader_Ojors的脚印】在Shader之前_基础数学_第6张图片
左手法则/右手法则 (图截自《3D数学基础:图形与游戏开发》)

【UnityShader_Ojors的脚印】在Shader之前_基础数学_第7张图片
叉乘 (图截自《3D数学基础:图形与游戏开发》)

叉乘结果向量的大小由以下公式给出:
![][8]
[8]: http://latex.codecogs.com/png.latex?\left|a\times{b}\right|=\left|a\right|*\left|b\right|\ast\sin\theta

矩阵

先下个简单的定义:
如果说向量是标量的数组,矩阵则是向量的数组。

在Unity中,方阵较为常用。方阵是行跟列维数相同的矩阵:
![][10]
[10]:http://latex.codecogs.com/png.latex?\begin{bmatrix}1&2&3\4&5&6\7&8&9\end{bmatrix}
当非对角线元素全为0,则称这种矩阵为对角矩阵:
![][11]
[11]:http://latex.codecogs.com/png.latex?\begin{bmatrix}1&0&0\0&2&0\0&0&3\end{bmatrix}
当对角矩阵对角线全为1,则称该矩阵为单位矩阵:
![][12]
[12]:http://latex.codecogs.com/png.latex?\begin{bmatrix}1&0&0\0&1&0\0&0&1\end{bmatrix}

矩阵乘法

为方便起见,以二维矩阵为例子:
![][15]
[15]:http://latex.codecogs.com/png.latex?\begin{bmatrix}a_{11}&a_{12}\a_{21}&a_{22}\end{bmatrix}\begin{bmatrix}b_{11}&b_{12}\b_{21}&b_{22}\end{bmatrix}=\begin{bmatrix}a_{11}b_{11}+a_{12}b_{21}&a_{11}b_{12}+a_{12}b_{22}\a_{21}b_{11}+a_{22}b_{21}&a_{21}b_{12}+a_{22}b_{22}\end{bmatrix}

向量与矩阵的乘法

![][16]
[16]:http://latex.codecogs.com/png.latex?\begin{bmatrix}x&y&z\end{bmatrix}\begin{bmatrix}m_{11}&m_{12}&m_{13}\m_{21}&m_{22}&m_{23}\m_{31}&m_{32}&m_{33}\end{bmatrix}=\begin{bmatrix}xm_{11}+ym_{21}+zm_{31}&xm_{12}+ym_{22}+zm_{32}&xm_{13}+ym_{23}+zm_{33}\end{bmatrix}
![][17]
[17]:http://latex.codecogs.com/png.latex?\begin{bmatrix}m_{11}&m_{12}&m_{13}\m_{21}&m_{22}&m_{23}\m_{31}&m_{32}&m_{33}\end{bmatrix}\begin{bmatrix}x\y\z\end{bmatrix}=\begin{bmatrix}xm_{11}+ym_{12}+zm_{13}\xm_{21}+ym_{22}+zm_{23}\xm_{31}+ym_{32}+zm_{33}\end{bmatrix}
由上可见,行向量左乘矩阵,结果是行向量;列向量右乘矩阵,结果是列向量。
(Ps:在Unity中,常把向量方在矩阵的右侧,即使用列向量进行运算。此种情况下,我们阅读的顺序应为从右往左阅读,即:CBAv为对向量v先进行A矩阵变换,再进行B,最后进行C矩阵变换。矩阵变换请往后看)

矩阵的几何意义

矩阵常用与坐标系的转换。
先给出理解:矩阵中的每一行都能解释为转换后的基向量(基向量:坐标轴向量,在三维空间中维X,Y,Z轴,当长度为1时称为标准基向量)。
先用2维坐标为例:
对变换矩阵:
![][18]
[18]:http://latex.codecogs.com/png.latex?M=\begin{bmatrix}2&1\-1&2\end{bmatrix}

【UnityShader_Ojors的脚印】在Shader之前_基础数学_第8张图片
坐标轴变换 (图截自《3D数学基础:图形与游戏开发》)

如上图所示:x轴从水平单位长度转换到点p(2,1),y轴从垂直单位长度转换到点q(-1,2);也就是说,该矩阵所达到的效果是让坐标系旋转角度并比例放大,换个说法,坐标轴从原来的坐标系转换到了新的坐标系了。

【UnityShader_Ojors的脚印】在Shader之前_基础数学_第9张图片
转换效果 (图截自《3D数学基础:图形与游戏开发》)

上图可以看到转换效果:旋转并放大

下面看看3维坐标的效果:
3D变换矩阵:
![][19]
[19]:http://latex.codecogs.com/png.latex?\begin{bmatrix}0.707&-0.707&0\1.250&1.250&0\0&0&1\end{bmatrix}

【UnityShader_Ojors的脚印】在Shader之前_基础数学_第10张图片
原效果 (图截自《3D数学基础:图形与游戏开发》)
【UnityShader_Ojors的脚印】在Shader之前_基础数学_第11张图片
转换后 (图截自《3D数学基础:图形与游戏开发》)

可以看到,变换矩阵中每一行对应变换X,Y,Z轴,该变换矩阵的效果为沿Z轴旋转45°,并进行不规则缩放。

我们可以得出结论:
  • 方阵的行能被解释为坐标系的基向量
  • 向量乘以一个矩阵,将从原坐标系变换到新坐标系
  • 从原坐标系到这些基向量定义的新坐标系的变换是一种线性变换。线性变换保持直线和平行线,但角度、长度、面积或体积可能会被改变。

转置矩阵

转置矩阵即为沿对角线翻转的矩阵:
![][13]
[13]:http://latex.codecogs.com/png.latex?{\begin{bmatrix}1&2&3\4&5&6\7&8&9\end{bmatrix}}^T=\begin{bmatrix}1&4&7\2&5&8\3&6&9\end{bmatrix}
对于向量,行向量变为列向量为:
![][14]
[14]:http://latex.codecogs.com/png.latex?{\begin{bmatrix}1&2&3\end{bmatrix}}^T=\begin{bmatrix}1\2\3\end{bmatrix}
转置矩阵的性质:
![][21]
[21]:http://latex.codecogs.com/png.latex?(MT)T=M,(AB)T=BTA^T

逆矩阵

不是每个矩阵都会有逆矩阵,首先的前提条件是,该矩阵是方阵。
逆矩阵的性质:矩阵M和其逆矩阵相乘,其结果是单位矩阵。
![][20]
[20]:http://latex.codecogs.com/png.latex?MM{-1}=M{-1}M=I
如果一个矩阵有逆矩阵,那我们就说这个矩阵是可逆的。简单判断一个矩阵是否可逆的方法是,求这个矩阵的行列式,如果结果不为0,则这个矩阵是可逆的。(行列式的求解以及怎么求取逆矩阵,过程相对比较复杂,大家可以查阅其他资料)

逆矩阵的性质:
![][22]
[22]:http://latex.codecogs.com/png.latex?(M{-1}){-1}=M,(MT){-1}=(M{-1})T,(AB){-1}=B{-1}A^{-1}
在三维变换中,我们经常需要通过逆矩阵来求解反向的变换

正交矩阵

正交矩阵是其与其转置矩阵的乘积是单位矩阵的矩阵,即:
![][23]
[23]:http://latex.codecogs.com/png.latex?MMT=MTM=I
大家可以对比逆矩阵的性质
![][24]
[24]:http://latex.codecogs.com/png.latex?MM{-1}=M{-1}M=I
我们可以得出一个很有用的信息:
如果一个矩阵是正交矩阵,我们可以通过求转置的方式求出其逆矩阵,这将可以大大较少运算量
正如名字一样,这种矩阵的3个基向量分别是正交关系,即相互垂直,由于
![][25]
[25]:http://latex.codecogs.com/png.latex?MM^T=\begin{bmatrix}-&c_1&-\-&c_2&-\-&c_3&-\end{bmatrix}\begin{bmatrix}|&|&|\c_1&c_2&c_3\|&|&|\end{bmatrix}=\begin{bmatrix}c_1c_1&c_1c_2&c_1c_3\c_2c_1&c_2c_2&c_2c_3\c_3c_1&c_3c_2&c_3c_3\end{bmatrix}=\begin{bmatrix}1&0&0\0&1&0\0&0&1\end{bmatrix}
可以看出矩阵的每一行c1,c2,c3必须为单位矢量,只有这样点乘的结果才能是1。
也就是说,我们有很简单的方式来知道一个矩阵是否为正交矩阵,即
c1,c2,c3均为单位矢量并且相互垂直


边忙边写写了好几天,终于写好了。。。数学真是一门神奇的学科。

你可能感兴趣的:(【UnityShader_Ojors的脚印】在Shader之前_基础数学)