向量

点积

在这里插入图片描述

点积性质

在这里插入图片描述

点积的作用

  • 计算两个向量的夹角
    在这里插入图片描述
  • 计算一个向量在另一个向量上的投影
    在这里插入图片描述
  • 衡量两个向量方向的接近程度
    两个单位向量同向时点积为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] axayazbxbybzcxcycz100=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=RT,注意这里是先平移后旋转。(而仿射变换是先旋转后平移,因此不能直接将旋转和平移矩阵填入到仿射变换矩阵中)

因此问题的重点是计算反向旋转矩阵 R r e v e r s e R_{reverse} Rreverse。参考上面说的任意坐标空间之间的变换矩阵的计算方法,我们只要找到变换后的三个轴即可,然后分别填入到矩阵的3个列中。

  1. 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
  2. Y轴,默认的up方向就是Y轴为 ( 0 , 1 , 0 ) (0,1,0) (0,1,0),而变换后的Y轴就是当前camera的up方向,设为 U p Up Up,即变换后的Y轴为 U p Up Up
  3. X轴,默认的x轴就是 ( 1 , 0 , 0 ) (1,0,0) (1,0,0),而变换后的X轴可通过叉乘计算得到,为 U p 叉 乘 − L o o k A t Up叉乘-LookAt UpLookAt,这就是变换后的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)

推导投影矩阵

详见GAMES101投影矩阵推导详解和分析

作业1

作业1主要是练习推导几个矩阵,如果弄明白了以上所有重点,难度不大。由于GAMES101课程作业是要循环使用的,按照闫老师所说,不要直接把作业代码放到开源网站上。所以我也就不直接贴作业代码了。但是我综合GAMES101的光栅化部分的理论和方法,基于Unity实现了一个软件光栅器,可以在Unity的Game窗口叠加Unity自己的camera渲染的效果进行比较,可以比较直观的判断有没有写错。目前基本的矩阵变换和光栅化已经完成,可以作为一个参考。
URasterizer
项目地址:https://gitcode.net/n5/urasterizer

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐