[GAMES101]现代计算机图形学课程总结1:线性代数和变换,作业1
文章目录向量点积点积性质点积的作用叉积叉积性质使用矩阵表示叉积叉积的作用变换仿射变换关于推导任意空间变换矩阵推导视图变换矩阵推导投影矩阵作业1向量点积点积性质点积的作用计算两个向量的夹角计算一个向量在另一个向量上的投影衡量两个向量方向的接近程度两个单位向量同向时点积为1,反向时为-1,为0时互相垂直。点积大于0时,点积越接近1说明方向越趋于相同。点积小于0,点积越接近-1说明方向越趋向于不同。分解
向量
点积

点积性质

点积的作用
- 计算两个向量的夹角

- 计算一个向量在另一个向量上的投影

- 衡量两个向量方向的接近程度
两个单位向量同向时点积为1,反向时为-1,为0时互相垂直。点积大于0时,点积越接近1说明方向越趋于相同。点积小于0,点积越接近-1说明方向越趋向于不同。 - 分解向量

在坐标轴上分解向量,只要将向量投影到其中一个坐标轴上,平行向量使用原向量减去投影向量得到。
- 判断前后关系

如图,向量a表示当前物体的朝向,那么其他物体的位置在当前物体前面还是后面,只要从当前物体指向其他物体的位置构造出一个方向向量,例如图中的向量b和c,计算点积,如果大于0则该点在物体前方,小于0则在后方。
叉积

叉积性质

使用矩阵表示叉积

叉积的作用
- 判断左右

所谓向量b在向量a的左侧,是指向量a向左旋转(逆时针旋转)得到向量b。右侧则是向右旋转(顺时针旋转)。
如图,为了判定向量b在向量a的左侧还是右侧,在a,b所在的局部坐标系中进行考察,其中a,b所在的平面为xy平面(当然也可以是其他坐标平面如yz,zx)。计算 a 叉积 b,为红色的向量(本课程使用右手坐标系),因为此叉积的z值大于0,那么b在a的左侧。同样,为了判定向量a在b的右侧,计算b叉积a,得到蓝色的向量,此向量的z值小于0 ,因此a在b的右侧。
通过叉积的z值判定旋转是向左还是向右,其实是判断旋转方向是否和坐标系的正旋转方向一致。对于右手坐标系,逆时针为正,因此a向左逆时针旋转到b的叉积也应该和z轴同向。对于左手坐标系,逆时针为负,因此a向左逆时针旋转到b得到的叉积是和z轴反向的。 - 判断内外

如图,判断点P是否在三角形ABC内部。当ABC顺时针排列时,判断P在AB的左侧(通过AB叉积AP判断),同样判断P在BC的左侧(通过BC叉积BP判断),以及判断P在CA的左侧(通过CA叉积CP判断),当P同时在这三条边左侧时即可判断P在三角形内部。而当ABC逆时针排列时,点P在ABC内部的条件为点P同时在三条边的右侧。所以无论ABC是顺时针还是逆时针排列,当P同时在三条边同一侧(左侧或右侧)时,P在三角形内部。
变换
仿射变换
- 仿射变换=线性变换+平移

- 使用齐次坐标表示仿射变换


- 仿射变换的顺序:先进行线性变换,再进行平移变换
- 3D空间中,绕任意轴旋转的矩阵的计算方法:罗德里格斯旋转公式

推导出最终公式的过程较复杂,但思想很简单,就是将向量分解成平行和垂直与旋转轴的两个分量,对于平行分量不会旋转,所以只要计算垂直分量的旋转,这是一个2D旋转,然后将旋转后的垂直分量和平行分量再加起来。推导公式的难点是最后要满足公式的形式,网上可以搜索到推导过程。个人觉得没必要研究这个(目前没发现用的地方),因为如果只是为了得到绕任意轴的旋转矩阵,按照上面的思路还是比较容易推导出矩阵的,况且实际3D引擎中已经很少直接使用旋转矩阵了,要么就是使用欧拉角最终合并成矩阵(大部分情况是够用的),要么就是使用四元数表示旋转,最后再转换成旋转矩阵。
另外公式中最后一项的3x3矩阵其实就是叉积。
关于推导任意空间变换矩阵
其实只要计算三个单位向量变换后的向量即可,然后将三个变换后的向量填到矩阵的3个列中(对于矩阵向量乘法,矩阵在左侧的惯例来说)。例如:
向量 ( 1 , 0 , 0 ) (1,0,0) (1,0,0)变换到新的坐标空间之后,在新的坐标空间中的向量为 ( a x , a y , a z ) (a_x, a_y, a_z) (ax,ay,az)
向量 ( 0 , 1 , 0 ) (0,1,0) (0,1,0)变换到新的坐标空间之后,在新的坐标空间中的向量为 ( b x , b y , b z ) (b_x, b_y, b_z) (bx,by,bz)
向量 ( 0 , 0 , 1 ) (0,0,1) (0,0,1)变换到新的坐标空间之后,在新的坐标空间中的向量为 ( c x , c y , c z ) (c_x, c_y, c_z) (cx,cy,cz)
那么我们可以得到从老坐标空间变换到新坐标空间的变换矩阵是:
[ a x b x c x a y b y c y a z b z c z ] \left[\begin{matrix} a_x & b_x & c_x \\ a_y & b_y & c_y \\ a_z & b_z & c_z \end{matrix}\right] ⎣⎡axayazbxbybzcxcycz⎦⎤
这其实很容易验证,因为这样得到的矩阵,用来变换单位向量,例如 ( 1 , 0 , 0 ) (1,0,0) (1,0,0)
[ a x b x c x a y b y c y a z b z c z ] ∗ [ 1 0 0 ] = [ a x a y a z ] \left[\begin{matrix} a_x & b_x & c_x \\ a_y & b_y & c_y \\ a_z & b_z & c_z \end{matrix}\right] * \left[\begin{matrix} 1 \\ 0 \\ 0 \end{matrix}\right] = \left[\begin{matrix} a_x \\ a_y \\ a_z \end{matrix}\right] ⎣⎡axayazbxbybzcxcycz⎦⎤∗⎣⎡100⎦⎤=⎣⎡axayaz⎦⎤
推导视图变换矩阵
视图矩阵的作用是将场景中所有物体的顶点变换到Camera默认位置朝向所确定的空间即视图空间中(例如GAMES101的规范中,camera默认在世界坐标系中朝向负Z轴,Up方向为正Y轴,且Camera位于世界原点)。而Camera本身可处于世界空间任意位置且朝向和up方向也任意。注意到物体和camera同时做同样的移动旋转时,他们是相对静止的,画面不会改变。因此视图矩阵只要能将camera从当前位置朝向变换到默认位置朝向即可。如何计算这个矩阵呢?
- 首先我们要将camera移动到默认位置即原点,使用一个平移矩阵 T = ( − C a m e r a X , − C a m e r a Y , − C a m e r a Y ) T=(-CameraX,-CameraY,-CameraY) T=(−CameraX,−CameraY,−CameraY)即可。
- 然后我们要将camera从任意朝向以及up方向旋转到默认朝向和up方向。这个旋转不是那么容易确定。但是很容易确定反方向的旋转。即从默认朝向以及Up方向旋转到当前朝向和up方向。我们只要计算出这个方向旋转矩阵 R r e v e r s e R_{reverse} Rreverse,然后对其求逆,即可得到旋转矩阵 R R R。
- 最后我们只要将旋转矩阵和平移矩阵合并,即可得到视图变换矩阵 M v i e w = R ∗ T M_{view} = R * T Mview=R∗T,注意这里是先平移后旋转。(而仿射变换是先旋转后平移,因此不能直接将旋转和平移矩阵填入到仿射变换矩阵中)
因此问题的重点是计算反向旋转矩阵 R r e v e r s e R_{reverse} Rreverse。参考上面说的任意坐标空间之间的变换矩阵的计算方法,我们只要找到变换后的三个轴即可,然后分别填入到矩阵的3个列中。
- Z轴,从默认朝向 ( 0 , 0 , − 1 ) (0,0,-1) (0,0,−1)经过变换后得到的朝向就是当前camera的朝向,设为 L o o k A t LookAt LookAt,由于 ( 0 , 0 , − 1 ) (0,0,-1) (0,0,−1)对应了 L o o k A t LookAt LookAt,所以 ( 0 , 0 , 1 ) (0,0,1) (0,0,1)对应了 − L o o k A t -LookAt −LookAt,即变换后的Z轴为 − L o o k A t -LookAt −LookAt
- Y轴,默认的up方向就是Y轴为 ( 0 , 1 , 0 ) (0,1,0) (0,1,0),而变换后的Y轴就是当前camera的up方向,设为 U p Up Up,即变换后的Y轴为 U p Up Up
- X轴,默认的x轴就是 ( 1 , 0 , 0 ) (1,0,0) (1,0,0),而变换后的X轴可通过叉乘计算得到,为 U p 叉 乘 − L o o k A t Up叉乘-LookAt Up叉乘−LookAt,这就是变换后的X轴。
经过此三步,我们已经得到变换后的x,y,z轴了,那么直接填入矩阵的3个列就得到了从camera默认位置变换到当前位置位置的旋转矩阵 R r e v e r s e R_{reverse} Rreverse,然后由于旋转矩阵是正交矩阵,那么其逆矩阵就是其转置矩阵,所以可以很容易得到其逆矩阵,也就是视图变换中的旋转矩阵 R = T r a n s p o s e ( R r e v e r s e ) R = Transpose(R_{reverse}) R=Transpose(Rreverse)
推导投影矩阵
作业1
作业1主要是练习推导几个矩阵,如果弄明白了以上所有重点,难度不大。由于GAMES101课程作业是要循环使用的,按照闫老师所说,不要直接把作业代码放到开源网站上。所以我也就不直接贴作业代码了。但是我综合GAMES101的光栅化部分的理论和方法,基于Unity实现了一个软件光栅器,可以在Unity的Game窗口叠加Unity自己的camera渲染的效果进行比较,可以比较直观的判断有没有写错。目前基本的矩阵变换和光栅化已经完成,可以作为一个参考。
项目地址:https://gitcode.net/n5/urasterizer
更多推荐


所有评论(0)