入门图形学2——位置与方向
2.1 点
- 在上一节我们讲到,坐标系是图形学以及数学物理学等等学科中非常重要而基本的概念
- 坐标系又是有一系列离散的点(离散就是分散开的不连续的)组成的。
- 那么在这里我们就可以很简单的定义点:
2.1.1 点的定义
- 图形学中点 是坐标系中的一个位置,同时也是一个数组,记录这这个点所代表的值我们称为坐标
- 点具有数值,维度这两个特征,并且是唯一的。
2.2 向量
2.2.1 物理学家眼里的向量
- 在物理学中,向量也被称为矢量,它更多是描述一种运动,包含了运动的速度和方向,它的位置是没有意义的,可以在任何位置出现,下面是一个简单的例子
2.2.1物理学家眼中的向量
- 这是一个三维空间里的向量分布,可以看出它们仅仅代表着不同的方向以及长度大小,它们的颜色值是根据数值对应的RGB颜色计算出来的(就像我们上节课所了解到的)
- 这是一种理解方式,但计算机学家眼中,还有另一种理解。
2.2.2 计算机学家眼里的向量
- 计算机学家眼中,向量与物理学家眼中的不太相同,我们更多只在意它的数值特征,毕竟计算机的根本就是一组一组的数据运算(详细可在计算机基础入门中了解)
- 因此在他们眼里,向量也许是这样的:
2.2.2 计算机学家眼中的向量
- 在这个例子中,我们记录的两个数本身有自身所代表的含义,而我们却忽略了其位置,毕竟一个房屋的售价和平米而言,位置信息对他们是无效的。
- 而数学家却尽力概括这两个观点,他们就提出了我们所学习到的数学上对向量的定义
2.2.3 向量的定义
- 向量是在坐标系下,以原点为起点的有一定距离的有向线段。
- 本质上它们表示的是两点之间的差异,或者说是一个点如何变化到另一个点的指示。
- 向量与点类似,同样具备两个特征,那就是方向(所指的角度)以及大小(它的长度)
- 在计算机中,向量往往作为变化的一种手段,我们可以利用它进行物体或者数值的变换,这种变换是对于坐标系而言的。
2.2.4 基本的向量的运算
- 点与向量的运算
- 点的减法运算
- 向量是两点只差,有了这个根据我们就可以通过两点位置的计算来表示一个向量,比如从P点到O点的运动方式,我们就可以理解为一个向量,让我们表示它!
- O(Ox,Oy) - P(Px,Py) = Vpo
- 我们一定要从几何直观上理解它,就像这样:
2.2.4 点与向量的运算
- 点的加法运算
- 实际上我们已经可以描述点的加法运算了,它本质上只是减法的逆运算,因此我们可以描述P到O的运算,就像这样:
- P(Px,Py) + Vop = (Ox,Oy)
- 描述的实际上还是这个过程,很容易理解。
- 点的减法运算
- 向量之间的运算
- 向量与向量的加法
- 向量之间的加法本质上也可以用过点来定义,因为前文告诉我们实际上向量也是由点来表述的,因此我们可在二维坐标系下,定义一个向量的加减法,就像我们定义点与向量的运算一样
- 点P(Px,Py) ,(Ox,Oy) ,Q(Qx,Qy)
- 向量:O(Ox,Oy) - P(Px,Py) = Vpo,Q(Qx,Qy) - P(Px,Py) = Vpq
- 所以
- Vpo + Vpq = O(Ox,Oy) - P(Px,Py) +Q(Qx,Qy) - P(Px,Py)
= (Ox+Qx - 2Px,Oy + Qy - 2Py)
- Vpo + Vpq = O(Ox,Oy) - P(Px,Py) +Q(Qx,Qy) - P(Px,Py)
- 计算很简单,但我们如何去描述它呢,实际上它让我们做了什么?
- 前文提到,计算机中向量的运算实际上就是改变一个数的值,我们完成的实际上是一个全局尺度的变换。
- 从P出发我们先到了O,此时如果用我们上面的值来表示(Px + Ox - Px,Py+ Oy - Py)最后运算得到的就是O点,而后我们再向着Vpq所代表的方向运动那就是(Ox + Qx -Px,Oy + Qy - Py)。为何与上面的结果有所不同?
- 细心地同学会马上指出,你求得的结果是个点啊!
- 没错,我们上面推导的实际上是对于一个点而言的变化,而前面所推的则是向量的加减法。他们有什么区别?没错,因为向量是忽略位置而只是一个操作,所以我们没有加上最开始的点坐标。而他们之间其实就是这个差别。
- 由此我们系统的论证了为何向量是指示一个点到另一个点的变化。这种加法法则也被称为向量的四边形法则:
2.2.4.1向量的四边形法则
- 向量与向量的加法
- 向量的数乘
- 向量的数乘实际上并不难理解,数乘可以看做一个缩放操作,是只对于向量的数值大小进行的变化
- 但同样会有一个例外:如果乘数是个负数,那么就会导致向量变化为反方向的一个新向量,相当于向反方向进行缩放。
- 向量的模
- 向量的模|a|其实就是描述向量长度的方式,这个需要运用一定的勾股定理去理解,实际上我们是将向量的分量作为描述模的方式也就是
- |a| = √ Ax^2 + Ay^2
- 向量的模|a|其实就是描述向量长度的方式,这个需要运用一定的勾股定理去理解,实际上我们是将向量的分量作为描述模的方式也就是
- 向量的归一化
- 向量的归一化是保留向量方向信息而忽略其长度信息的一种操作。比如在计算光线与法线的过程中,我们只需要知道方向信息就可以了,而过多的信息会造成数据存储的浪费,而如何进行这个操作呢
- 我们观察模的定义,会发现,如果我们想让模为1,实际上只需要将一个向量的每一个值除以他们的模,这是个很巧妙的数学方法
- 基向量
- 现在,我们终于可以介绍这个概念了,基向量是我们描述一个坐标系的方式,往往一对或几对相互垂直的基向量使我们定义一个基本的坐标系空间的方式,他们的特点是:模长为1,方向相互垂直,本质上是便于我们通过这个向量,来描述其他向量。如我们之前的Vpo向量就可以写成:
- Vx = (Ox - Px)* Xi , Vy = (Oy - Py )* Yi
- 这样做什么好处,好像根本没有什么变化啊!?毕竟模长是1乘上去压根不会有什么变化
- 实际上,这就是我们本次课或者说图形学最终的运行逻辑。就是通过变换基向量来进行空间的变换。试想一下,如果变换每一个向量每一个点来转换一个模型是不是会很麻烦?
- 那么如果我们变换基向量本身呢?没错,这样的话我们就可以很简单的将一个空间理所应当的改变为另一个空间了,而不用变换里面的每一个点。因为点本身就是这些基向量形成的,本质只是数乘而已。
2.2.4.2 三个基向量张成一个向量空间
- 现在,我们终于可以介绍这个概念了,基向量是我们描述一个坐标系的方式,往往一对或几对相互垂直的基向量使我们定义一个基本的坐标系空间的方式,他们的特点是:模长为1,方向相互垂直,本质上是便于我们通过这个向量,来描述其他向量。如我们之前的Vpo向量就可以写成:
- 向量的乘法
- 点积
- 点积是向量与向量相乘的结果,它最后得到的是一个数,公式如下
- a·b = axbx + ayby
- 点积不但可以描述角度信息也可以描述一个向量再另一个向量方向上的投影长度
- a·b = |a||b|cos<a,b>
- 通过这个公式我们可以快速得出a,b之间夹角值,以及ab的大致方向判断。
- 点积是向量与向量相乘的结果,它最后得到的是一个数,公式如下
- 点积的特性使我们可以利用它将一个向量分为水平方向和垂直方向的分向量,为我们后期描述向量之间的关系提供了一个有力手段。
- 点积的实际应用:
- 比如在计算光线与物体法线的关系中,我们就可以通过点积运算快速得出一个物体的受光信息:
2.2.4.3 点积的应用——判断着色
- 叉积
- 叉积是向量之间的另一种运算,不同的是,它只适用于3维计算,它得到的不是一个数而是一个向量。
- a×b = 【aybz - azby,axbz - azbx,axby - aybx】
- axb = (aybz - azby)x +(axbz - azbx)y +(axby - aybx)z
- 叉积描述的是一个垂直于相乘的两个向量所构成平面的向量,因此往往应用于求解法向量。
- 叉积同样可以描述两个向量之间的角度关系
- a×b = |a||b|sin<a,b>
- 但需要注意的是,叉积可能会存在两个不同结果,这显而易见,因为垂直于ab平面的向量有两个,如何去判别他们呢?
- 我们可以通过平移向量使他们首尾相连,并判断是顺时针还是逆时针方向,通过左右手坐标系来判别他们的方向
2.2.4.4 叉积存在两个方向
- 叉积是向量之间的另一种运算,不同的是,它只适用于3维计算,它得到的不是一个数而是一个向量。
- 叉积的应用
- 判定左右
- 前文我们提到,叉积有两个方向,并且我们可以根据方向的不同判定原始向量的旋向性,那么由此,我们就可以判断这两个向量之间的左右关系了,比如顺时针的方向排布,b在a的左边
2.2.4.5 插件的应用——判断左右
- 判断内外
- 这是一个很重要的应用那就是判断一个点是否在三角形内,这会在我们后续的光栅化阶段应用。我们可以依次连接一点与一个三角形顶点,并将其作为一个向量与三角形顶点组成的向量做叉积,如果三个顶点判断都为同一侧(左侧或者右侧)我们就将其判定为在三角形内,并渲染这个点到屏幕上。
2.2.4.6叉积的应用——判断内外
- 点积
进阶2.3 在Processing中实践
2.3.1 向量加减法的直观实现
我们通过Processing来定义两个向量构造函数,在Processing中我们进行如下定义,首先我们需要定义一个Pvector基类来实现向量,如下:
在这些代码中,我们分别创建了三个向量对象,并且为他们赋值,让他们分别在xy上有了对应的值,因此我们可以在ellipse这个函数之中传入我们创建的对象的值,这样,我们就可以在想对应的坐标处为中心,创建圆形,add参数本质上就是将向量的对应坐标相加,得到v3的值。
效果如下:
2.3.2 点乘的直观实现
同样,我们在其中使用dot函数,就可以进行点乘。我们还是定义两个向量,并且传入两个向量的位置,调用line绘制两条线段,而后,我们将v2标准化,也就是作为1,并且我们将标准化后的v2,作为值与v1进行点积,实际上我们得到的就是v1在v2上的投影,而后我们将v2乘上这个投影,并且绘制,就可以得到如下图形:
2.3.3向量叉乘的直观实现:
叉乘本质上就是先进行两个向量的标准化,也就是与基向量点乘,而后,将它们赋值给一个新的向量。这个新的向量就是标准化之后的向量。
我们来看一下它的实现
首先我们新建两个变量,然后在中心位置新建一个点,我们在这个点为基准,绘制两条支线,然后以这两条支线为基准,使用叉乘函数生成我们的第三条线段,它是垂直于另外两条线段的,然后我们将它标准化,也就是除以模长,之后,绘制:效果如下图:
参考资料
- 计算机图形学入门——3D渲染指南 GabrielGambetta著 贾凡译
- games101图形学入门——闫令琪 https://www.bilibili.com/video/BV1X7411F744
- 游戏开发入门——数学和物理 徐芝琦等著
- UnityShaderLab新手宝典 唐福幸著
- Shader开发实战 KyleHalladay著 郭华丰 韦静译
- DirectX12 3D游戏开发实战(龙书)Frank D.Luna 著 王臣译
- 【【官方双语/合集】线性代数的本质 - 系列合集】 https://www.bilibili.com/video/BV1ys411472E/?p=2&share_source=copy_web&vd_source=18d60239a339ad21d3b3f050742622f4
- Fundamental Of ComputerGraphics(虎书)by Steve Marschner
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Pleasant233!