第二章 - 数学工具
本章节篇幅较大并主要介绍一些数学工具而不是他们在计算机图形学中的应用。因个人为数学与计算机双专业学生,不在个人笔记中记录数学语言及常见概念。笔记本章仅解释一些重难点内容以及数学工具在计算机图形学的应用,基础部分将以索引文献或网站的方式呈现。
1. 集合与映射(Set and mapping)
相关概念可在大部分基础数学书中找到,此处附简单介绍链接(集合与映射 、 映射与函数),如果依然存在理解问题可详细查询*。对于程序员来讲,一个熟悉的例子是哈希函数的映射与逆映射,或者更广泛的键值对(key-value pair)。
在对不同的2D与3D图形的碰撞检测问题中,区间(interval)的概念可以帮助我们更好分析碰撞条件。区间可以简单的理解为一段线段、一条射线或者直线,然后额外增加是否包含端点的信息。例如\((0,1]\)就是0至1的线段但不包含0。做算法题较多的会有线段树、排课表等问题用到区间。
另外一个数学工具是log函数(对数),其数学操作见链接,在写程序时大部分操作均有数学库支持,注意是否存在解的问题就行了(例如ln(-2)会到复数域)。
2. 解二元一次方程
初中知识的常用公式即可,例如\(\Delta = b^2-4ac\) 、中值的\(-\frac{b}{2a}\)以及第一项\(a\)的符号决定最高点还是最低点即可。其他可见百度百科链接
3. 三角函数
角度
分为弧度(radian)和角度(degree),这两个有公式可以互相转换。值得注意的是在很多计算机图形学的数学库中,每个函数对弧度和角度的要求各不一样,即在参数degree中,函数描述会标注是使用弧度还是角度来计算。编程时需格外注意。
三角函数
基于\(a^2+b^2=c^2\)的欧拉定则略,极坐标见链接,三角函数转换的一些公式如下。
值得注意的是在图形学中经常通过点乘计算\(cos(x)\)的值再算出角度,需要使用到三角函数的逆函数即\(asin,acos,atan,atan2\),这些函数因为存在无限个解(\(x+k*2\pi\)),常见的图形库会限制结果范围,具体见下图。需要额外注意的是函数\(atan2\),这个不是\(atan^2\),而说的是使用\(atan2(s,c)\)的两个输入(分别与\(sin,cos\)等比),返回真实角度,不需要根据图像是锐角还是钝角额外为\(atan\)的结果添加180度角。注意\(atan2\)返回四个象限,而\(atan\)只返回两个象限。
4. 向量
关于基本的定义、加减乘除、基(basis)、深层的群域环向量空间不再此赘述,可查阅线性代数与抽象代数相关书籍,此处附带一些链接与个人直觉上的解释以服务于数学基础较差的读者。需注意,数学意义和直觉理解相差较远,理解时应该带着直觉去理解数学意义的应用、寻找正例和反例。有关线性代数推荐三蓝一棕的线性代数视频
- 向量,满足向量空间内向量八个定理的都称为向量,向量空间的价值可以见抽象代数书籍,类比的话数学的群域(向量空间属于此类)环和计算机的数据结构类似,使用某种聪明的、经过设计的结构来满足自己的某种特殊需求(例如计算机的时空复杂度,数学的与某个领域重叠以解决问题)。
- 线性空间与基,向量的特点是它是线性的,直觉上理解就是按单位做直接运算的。与对数log或者10的n次方做区别,生活中常见的米,千克等均为线性单位,每一个单位1代表的价值是一样的。基的定义直觉来讲与单位这一概念类似,它选择决定了线性空间的样子。基缺了一个,多了一个都会导致空间性质改变的空间基础,此外基之间必须彼此无关。例如描述物体长宽高三者无关,合起来可以描述物体大小。如果基之间有关往往说明这个基不够简略需要简化。一个例子是利用中国个十百千万作为基来说八十七,而不是在给别人钱时使用一个50加三个10加一个5加两个1。
- 在讨论向量时,我们要确定在哪一个向量空间,是多项式函数、N维空间、实数还是复数。另外要注意基是什么,是\(\{1,x,x^2,...\}\)、二维的\(\{x,y\}\)还是三维的\(\{x,y,z\}\)等。
- 计算机图形学着重于二维与三维几何向量,即单纯的方向与长度,倾向于物理力学的处理方法而不是数学的抽象方法。
- 向量有点乘与叉乘两种,分别拥有代数意义和几何意义。点乘着重于投影和相似性,叉乘包括了更高维度的数据与两个向量之间平行四边形的面积。叉乘的理解见链接。一定要注意的是叉乘分坐标系,数学上通常使用右手坐标系,不同的数学库可能会使用不同的坐标系,例如Unity使用左手而OpenGL使用右手。
一个有意思的点是在游戏开发中,可能会存在全局坐标系与局部坐标系。一个常见的方案是将每个物体设置一个原点,原点在全局坐标系中有一个坐标。而每一个物体自己有一个局部坐标系,例如一个战士的剑在原点的右侧(1,0,0)处。通过全局原点坐标+局部坐标偏移我们可以快速计算出战士的剑在全局坐标的位置。这么做的好处是在移动物体时可以将物体作为整体移动,节约效率(整个人移动而不是鼻子眼睛耳朵分开,还可以避免程序出错)。显而易见的是局部坐标系和全局坐标系可以互不相同,不同物体的局部坐标系也可以不同,中间可能需要进行单位转换。
在摄像机系统里,我们经常使用forward, left/right, up三个方向来表示摄像机的局部坐标系,其中经常利用forward来计算其他两个基,即利用任何一个与forward不在同一直线的向量与forward叉乘来得到left(需要长度为1),然后用forward和left来叉乘计算up。
在坐标系的某个基在计算机内出现计算问题或存储精度问题时,我们可以根据其他正确的基重新计算(有效但会导致对三个基处理不公平)或者利用奇异值分解(SVD)的方法(更好的方法,算法略微复杂,后续补充)。
5. 曲线与曲面
此段内容在大部分的多元微积分书籍中有更为详细的阐述,本节仅收录主要概念和理解,个人使用的教科书是Multivariable Calculus 7th edition Huges-Hallett Gleason McCallum et al.
- 曲线是曲面的截面边,曲面是实体的截面。具体可以参考切西瓜,或者点线面维度的区别。例如上图可以沿着x轴,y轴,z轴,或者任何方法切,都会得到一条曲线。
- 我们可以通过函数来描述部分曲线和面,常见的函数形式是\(f(x,y)\),如果沿着\(x=2\)这条线切,那么曲线函数就是\(f(2,y)\)。
- 存在沿着x,y方向的偏微分,存在gradient梯度,是一个二维向量\(\nabla f=(\frac{\delta f}{\delta x},\frac{\delta f}{\delta x})\),沿着这个方向\(f(x,y)\)函数上升的最快,若等于0则为最高点或最低点,是最优化问题的核心之一。偏微分也可以用来分辨该点局部的函数形状。
- 直接函数\(f(x)=y,f(x,y)=z\)与隐式函数\(f(x,y)=0,f(x,y,z)=0\),隐式函数可以理解为从高维度取截面0并获得额外信息的好处,例如直线\(x=0\)在二维空间内不是函数并无法通过\(y=f(x)\)的方式表达,但在三维空间可以,效果是\(f(x,y)=x=0\)。
二维
隐式直线函数应用
对于任意两点(x_0,y_0),(x_1,y_1)求隐式公式\(Ax+By+C=0\),可得两点之间向量\((x_1-x_0,y_1-y_0)\)还有与之垂直的梯度向量\((A,B)\),简单选取任何点乘为0的向量作为梯度向量,如\((y_0-y_1,x_1-x_0)\)。简化至\((y_0-y_1)x+(x_1-x_0)+C=0\)代入任意一点可求解\(C\)。这个方法依然是使用在常规二维空间不构成函数的地方,否则简单利用直接函数\(y=kx+b,k=\frac{y_1-y_0}{x_1-x_0}\)代入求解即可。
对于任何点(a,b)距离直线\(f(x,y)=Ax+By+C=0\)的距离可以将\((a,b)\)转换为\((a,b)=(x',y')+k(A,B)\)来进行计算,注意这里\((x',y')\)为直线上的某一点,因此\(Ax'+By'+C=0\)。其次\((A,B)\)作为梯度是垂直于直线的,因此\(k||(A,B)||=k\sqrt{A^2+B^2}\)即\((a,b)\)到直线的距离。化简可得\(f(a,b)=f(x'+kA,y'+kB)=Ax'+kA^2+By'+kB^2+C=k(A^2+B^2)+0\)。因此,得到距离为\(k\sqrt{A^2+B^2}=\frac{k(A^2+B^2)}{\sqrt{A^2+B^2}}=\frac{f(a,b)}{\sqrt{A^2+B^2}}\)。这个技巧可能可以被用于OLS的快速运算,一定可以被用于三角形光栅化。
隐式二阶曲线
常用的形式为\(Ax^2+Bxy+Cy^2+Dx+Ey+F=0\),椭圆\(\frac{(x-x_c)^2}{a^2}+\frac{(y-y_c)^2}{b^2}+C=0\)和圆\((x-x_c^2)+(y-y_c)^2-r^2=0\)都比较多。
三维
切平面与法线
和之前一样,三维隐式指从四维借一维,但仅使用第四维的0,以此来获得一些额外信息以用于做到三维做不到的事。与二维一样,我们可以通过某个点\(P\)上的偏微分计算出该点\(P\)的梯度\(\nabla f(P)=(\frac{\delta f(P)}{\delta x},\frac{\delta f(P)}{\delta y},\frac{\delta f(P)}{\delta z})\),同时这个梯度与曲面在该点的切平面相垂直(二维圆的切线与三维球体的切平面是同理的),这个梯度也可以被理解为平面法线(surface normal)。显然,对于切平面上任意一点\(A\),我们知道\(A,P\)之间的向量\(P-A\)与梯度\(\nabla f(P)\)互相垂直,故点乘\((P-A)\cdot \nabla f(P)=0\)。与其逻辑相反,如果我们已知三点想求平面的公式,那么可以利用两组两个不同的点之间的向量差进行叉乘来获得平面法线,代替之前的\(\nabla f(P)\),得到类似于\((P-A)\cdot ((B-C)\times (A-C))=0\),另外将向量\(P\)化简成(x,y,z)的形式则可以获得常规的公式。另外一个几何方法是因为四点共面,向量\(P-A,B-A,C-A\)构成的六边形体积应为\(0\),因此如下矩阵的行列式也为\(0\),背后的原因可以参考叉乘公式与行列式的推导,在第五章节也会进行细节性的阐述,另外在三蓝一棕的线性代数的本质中也有简单介绍。
参数曲线
笼统来讲,参数曲线是通过调整参数来调整对应的单位来改变结果,整体上是类似于过程的形容。如之前在计算点到二维直线的距离时,我们把点分解成为\((a,b)=(x',y')+k(A,B)\),这里改变\(k\)就可以改变\((a,b)\),而对应的\((A,B)\)则是一个带有特殊意义(法线向量)的一个单位。从某种意义上来讲,基与参数曲线里的单位起到类似的效果,例如常规情况下的\((x,y)=xi+yj\)里面\(i,j\)是单位基,\(x,y\)则是参数,如果稍微改变一下定义方式,例如\((x,y)=x(1,1)+y(0,2)\),道理不变但这依然是一个参数直线。以下会介绍一些例子
-就二维直线而言,通常拆分为\(p(t)=p_0+t(p_1-p_0)\)的形式,其中\((p_1-p_0)\)往往代表一个有特殊意义的向量,直线的话则单纯为直线所在的正方向,把它化为单位向量则\(t\)可以直接表示距离。调整t指的是从原点开始画线。
-就二维圆而言,可以拆分为\((x,y)=(x_c,y_c)+(a\cos{\theta},b\sin{\theta})\),通过调整\(\theta\)角度来改变点在圆中的位置,利用了极坐标的方法,调整角度\(\theta\)会绘制一整个圆。
-就三维平面而言,通常拆分为\(p(t)=p_0+av_1+bv_2\),其中\(v_1,v_2\)是不共线的两个在平面上的向量。这个表达形式比起常规隐式函数拥有的好处是可以快速算出法线的值,直接利用\(n=v_1\times v_2\)即可,而不是计算某个点梯度。依次调整\(a,b\)会沿着对应向量画线
-就三维球体而言,在常规的\(x,y,z\)坐标外还拥有\(r,\theta,\phi\)的球坐标系,分别是半径以及横纵方向的偏移角度。依次调整\(r,\theta,\phi\)会在球面上沿着球心至点的射线方向与经纬线移动。
总的来讲,参数曲线内的拆分形式能给我们带来一些直观的信息,如建模一样可以标注一些参数与对应单位的信息以供人快速理解。相反常规函数包含的直观信息较少,需要有经验的人通过函数外表形式才能进行推断(例如圆特有的函数形式)。
小的回顾
至此应该有几个思考
- 二维与三维隐式函数的共同点是什么,为什么需要借一个维度,有什么好处,为什么借一个维度使用了\(f(x,y,z)=0\)的形式。
- 梯度与切线与法向量的关系是什么,切线说的是微观环境下与该点经过函数转换后值一样的点的集合,在宏观上来看不对,也可以表达变换速度等,通常是常规维度微分得出的,例如\(y=x^2\),取点\((0,0)\),因为微分值为\(2x=2*0=0\),且切线过\((0,0)\),得切线\(y=0x+0\)。梯度是借一维度后微分得出,如\(y=x^2,f(x,y)=y-x^2\),梯度为\((-2x,1)\),在\((0,0)\)上则是\((0,1)\),梯度代表的是在哪个方向上高维变动最快,该值是等值线/面的法向量,并显然与该点(在等值线上)的切线垂直。一个小讨论可以见此链接
- 基的选择与参数曲线的使用背后的逻辑是类似的,均是使用了一个更好理解或拥有更大意义的一个坐标系。个人认为一个较好的例子是特征值与特征向量分解,与参数函数的方法高度一致。
6. 线性插值
插值法的目的是已知一些点,希望能找到一个穿过这些点的一个连续函数。在计算机图形学中线性插值法有很多应用,一个小的前瞻则是假设一个三角形内有三个点,均有一个较为重要并希望三角形内每个点都拥有的信息(例如颜色),如果我们希望三角形内的点的该信息是基于三个点信息的某种混合,一个简单的做法则是通过线性插值,即越接近某个点则受该点的影响更大且总影响系数为1,具体算法见下一部分(7.三角形)。
就二维来讲,连接多个点的最简单方法是绘制连续的直线,把他们分为不同的区间,并把首尾定义为\(A,B\),则普遍来讲中间点为\((1-t)A+tB\),其中t是一个权重系数在0和1之间。
7. 三角形
三角形的面积可以通过叉乘值的一半来获得,具体原因是叉乘可以得到平行四边形的面积。在使用线性插值来模拟三角形内点的某个属性(例如颜色)时,我们通常通过重心坐标插值(Barycentric Coordinate Interpolation)来达到。这个方法在此链接有非常详细的描述,故我仅仅在此记录个人的一些注意事项。
定义与代数解法
已知共面三角形顶点\(A,B,C\),以任何一点例如\(A\)为基准,可得两个向量\(B-A\)与\(C-A\),形成参数平面\(A+p(B-A)+q(C-A)\)。对于平面上任何一点\(P\)可写为\(A+p(B-A)+q(C-A)\)的形式,等价变换可以获得\((1-\beta-\gamma)A+\beta(B-A)+\gamma(C-A)\)的形式。将\(1-\beta-\gamma\)记做\(\alpha\),则三角形平面上任何一点\(P\)可以写成\((\alpha,\beta,\gamma)\)的参数平面坐标形式,且\(\alpha+\beta+\gamma=1\)。
实用技巧
-如果\(\alpha,\beta,\gamma\)三个均在\((0,1)\)内,则点\(P\)在三角形内。
-如果\(\alpha,\beta,\gamma\)两个均在\((0,1)\)内且第三个为0,则点\(P\)在三角形的边上,是\(0\)所在顶点的对边。
-如果\(\alpha,\beta,\gamma\)仅有一个为1,其他两个为0,点\(P\)在值为0的顶点上。
-坐标\((\alpha,\beta,\gamma)\)除了表示坐标外也可以用于均匀的线性插值,例如颜色等。
几何解法
可以将参数记录为距离三角形点对边的相对距离,从下图可以看到,参数\(\beta\)代表点\(P\)距离\(b\)的对边\(AC\)的相对距离。如果\(\beta=1\),则点\(P\)与点\(b\)相对\(ac\)的距离是一致的。因此可以取对边的隐式函数\(f(x,y)=Ax+By+C\),可得任意点\(P\)到直线距离为\(\frac{f(a,b)}{\sqrt{A^2+B^2}}\),这样就可以算出\(\beta=\frac{f_{ac} (x_p,y_p)}{f_{ac} (x_b,y_b)}\)。在按此方法正确计算\(\beta,\gamma\)后,可以得出\(\alpha=1-\beta-\gamma\)。
面积法
从几何解法可以看出,参数的相对距离也可以理解为将底固定为对边后高的比,从而引申出如下的面积法。在实际使用面积法时一定要注意精度问题,有时会导致三个参数加起来不为1。
三维情况如下,其中\(n\)为法线向量。其中推导省略的部分是将三角形平面外的\(P\)通过点乘投影至三角形平面再计算面积,若确认在同一平面则直接使用\(\beta=\frac{||n_b||}{||n||}\)即可。这里从\(n_a,n_b,n_c\)的定义可以观察到向量是顺时针的,在此参数计算时影响较小,但在图形学很多操作中注意时针顺序是比较重要的。