3D Game Programming withDX11 学习笔记(一) 数学知识总结

时间:2023-03-09 02:49:38
3D Game Programming withDX11 学习笔记(一) 数学知识总结

  在图形学中,数学是不可或缺的一部分,所以本书最开始的部分就是数学知识的复习。在图形学中,最常用的是矢量和矩阵,所以我根据前面三个章节的数学知识,总结一下数学知识。

一、矢量

  数学中的矢量,拥有方向和长度。其实矢量和点在坐标系中的表示完全一致(笛卡尔坐标系为准),区分矢量和点的关键,我觉得就是做平移。点是不能用平移操作来保证一致的,比如点A(1,2,3)经过平移矢量(1,2,3)后就是B(2,4,6),此时就是一个新的点。但是矢量经过相同平移操作后,还是矢量(1,2,3),这是因为矢量表示的是 vector head相对于 vector tail的偏移,平移操作并不会改变这种偏移。

  在矢量中一个关键就是坐标系,数学中的坐标系主要分为左手坐标系和右手坐标系。我时不时会弄混左手和右手坐标系,后来做了一个快捷的记忆:我的头是y方向,右手伸出来是x方向,那么如果z方向向前是正方向,那我就处于左手坐标系; 如果我的z方向向后是正方向,那我就处于右手坐标系。所以看起来我的脸决定了我的坐标系:)

矢量的数学操作主要是:加、减、乘三种操作,如果算上求模(求长度),那就是四种操作。A=(xa,ya,za), B=(xb,yb,zb)

加:A + B = (xa+xb, ya+yb, za+zb)

   减:A - B  = (xa-xb, ya-yb, za-zb)

  乘:A *B   = xaxb+yayb+zazb

模:||A||2= xa2 + ya2+za2

细心的会发现矢量乘的结果变成了一个数,确实,最终的结果就是一个数,其本质就是一种映射或者投影,表示的是A矢量在B矢量方向上的投影长度,矢量的乘可以用公式表示为:

  A *B   = ||A|| *||B|| * sinθ,其中θ为两个矢量的夹角(由于不熟悉博客的数学公式添加,只有先这写着了,后面熟练了再修改吧)

矢量中最常见的操作就是归一化,比如有一个矢量的序列{V0,v1,V2...},如何将这些矢量归一化为互相垂直的单位矢量?

这儿引入投影的一个表示:projn(V)= v . n/||n||, 表示的是v在n的单位矢量上的投影,那么对于矢量序列,我们可以这样进行正交归一化:

1)v0, v1,v2.......

2) w0 = v0;

3) w1 = v1 - projw0(v1)

4) w2 = v2 - projw0(v2) - projw1(v2)

........

根据上面的规律,可以得到正交化的规律:将当前矢量(第一个除外)去除在前面所有矢量上的分量(投影),得到的就是与前面各个适量正交的矢量。

最后我们将正交化的矢量进行归一化操作,即可得到一组正交归一化矢量序列。

矢量的最后一个知识点是:矢量的叉积,与矢量点积得到一个投影的结果值不同,矢量的叉积得到的是一个矢量,基本公式为:

AXB = (yazb -zayb, zaxb - xazb, xayb - yaxb),

   单看公式看不出规律,不过可以这样理解:xyz, yzx, zxy,分别去掉x, y , z,最后的结果就是三个分量的第一项,然后交换得到三个分量需要减去的第二项

矢量的叉积的实际意义,就是求得一个和A/B两个矢量都垂直的矢量,这在图形学中,可以用来求解游戏对象的一些常用矢量, 比如上(up)/下(down)/左(left)/右(right)/前(forward)/后(back)这些矢量都是互相垂直的,可以利用矢量的叉积得到。注意在笛卡尔坐标系中,矢量的叉积都是左手定律决定方向的,所以AXB和BXA是刚好方向相反的两个等长矢量。

二、矩阵

  在图形学中,我们会绘制各种各样的游戏实例,这些实例都是用基本的点(verts)和相关的贴图(textures)、材质(material)等共同设置渲染状态的。对于基本的顶点,常常需要做的一个基本操作就是变换:平移、旋转、缩放等。这些变换操作对应的就是矩阵的变换。

矩阵的定义就不再多说,就是一个nxm的同类元素的集合,通常这个元素就是数字(也可以为其他,这儿不再扩展)。

矩阵最基本的操作可以分为: 矩阵的乘, 矩阵的转置, 矩阵的行列式, 矩阵的逆

矩阵的乘积:  C = AB ≠BA

C矩阵中的每个元素是Cij是A矩阵的i行和B矩阵j列的对应点积的结果,基于此可以得到A矩阵的列数和B矩阵的行数是相等的(不然怎么做点积....)

矩阵的转置AT,就是将矩阵的行和列对换,说的简单点就是一列一列的变,新的每列是以前矩阵的每行竖着排列(感觉就是重新排队)

矩阵的行列式,是一个比较重要的点,Aij作为行列式的代指,就是去除A矩阵的i行和j列后得到的行列式计算结果,整体的公式为:

detA = ∑j=1n A1j(-1)i+jdetA1j

可以看出矩阵的行列式计算就是一个递归的计算过程,一般在图形学中的计算不会超过4x4的维度,所以可以用笔算的方式来计算这些矩阵的行列式:)

基于行列式,可以得到一个新的矩阵: 邻接矩阵A*,基于基本的矩阵A可以得到一个新的矩阵CA,其中的元素Cij = (-1)i+jdetAij,则可以定义邻接矩阵为:

A* = CAT  基于邻接矩阵,我们可以得到矩阵A的逆矩阵A-1 :A-1 = A*/detA

三、变换矩阵

基于矩阵的定义,我们可以将图形学中的一些常见的变换转化为对应的变换矩阵,这样在对点或者矢量进行变换的时候,其对应的数学操作就是一个变换矩阵的操作。基本的变换矩阵可以分为:缩放矩阵, 平移矩阵,旋转矩阵。

对于变换矩阵对矢量的作用,可以这样理解:u =(x,y,z) = xi + yj + zk, 那么一个变换操作可以表示为τ(u) = τ(xi + yj + zk) = xτ(i) + yτ(j) + zτ(k) = [x y z] [τ(i) τ(j) τ(k)]T = uA

所以说的直白点,就是用矩阵A来表示一种变换操作。那么具体如何表示呢?可以分拆为基本矩阵,然后进行合并即可。

1、缩放矩阵S

拆开用行向量表示为S(i) = (sx .1, sy.0, sz.0), S(j) = (sx .0, sy.1, sz.0),S(k) = (sx .0, sy.0, sz.1)

则缩放矩阵可以表示为S = [si , sj, sk]T, si = (sx,0,0), sj = (0,sy,0), sk = (0,0,sz)

2、旋转矩阵R

其实旋转矩阵是三个矩阵中相对比较难的矩阵,这儿给出一个旋转公式:

Rn(V) =  projn(v) + Rn(V)

=  (n v) + cosθ V⊥  + sinθ (v)

=  cosθ V + (1 - cosθ)(n v)n + sinθ(v)

具体的常用的三个旋转矩阵可以列出来:

3D Game Programming withDX11 学习笔记(一) 数学知识总结3D Game Programming withDX11 学习笔记(一) 数学知识总结3D Game Programming withDX11 学习笔记(一) 数学知识总结

3、平移矩阵T

平移矩阵比较简单,就不做推算,直接给出结果即可:

3D Game Programming withDX11 学习笔记(一) 数学知识总结

综合三种基本矩阵,我们可以进行组合得到一个较为复杂的变换矩阵。不过在图形学的计算中,对于三种矩阵的排序有一定的讲究,一般先用缩放矩阵S对当前的变换对象进行缩放,然后用旋转矩阵R进行旋转操作,最后用平移矩阵T进行平移操作,所以可以归并为SRT矩阵

总结:经过基本的矢量,矩阵和变换的数学知识总结后,接下来就要进入正式的图形学知识了,我会在后面持续更新~