Games101 图形学入门笔记

几何

总览:我们把很多复杂的几何归分成两类,一类叫隐式,一类叫显式

演示图片

隐式表示

我们可以用一种函数f然后通过参数x,y,z的属于,然后函数所做的事就是返回这个点是否在3D的平面内外,通过这种方式我们可以知道点是否在我们定义的几何内外从而得到一个几何,比如我们这个图中举例,有一个球形,如果这个点在表面上就要满足x2+y2+z2等于0,那也就是说我们只要让f=0,就能得到这个球的表面上的所有点,这个函数只要满足f(x,y,z)=0即可

演示图片

但是隐式表示方法有一个难处就是只通过这个给出的函数式你是不知道哪些点在这个表面上的,说白了就是你不知道他最终是一个什么形状的几何,如下图1的圆环几何的表示,简单的地方也好理解,就是他可以很容易的判断出一个点是在我这个几何的里面还是外面还是上面,这就是隐式表示的特性

演示图片

演示图片

隐式的更多种表示方法

演示图片

CSG

通过对一个单独的几何进行布尔运算得到一些复杂的几何

演示图片

Distance Functions

简单理解就是找出空间中的点离当前这个物体表面的最小距离,而且是一个有符号值,在里面或者外面对应正负值,然后看下图中小球的融合产生新的形变,这种就是用Blending Distance Functions的方式做到的,也就是对距离函数进行插值

演示图片

Blending Distance Functions

简单说就是如果有两张图,然后两张图通过运动融合到一起的时候,我们希望看到的是一半黑的,一半白的,如果单纯对这两张图进行blend的话,会得到不对的结果,所以我们可以先对两张图做距离函数,也就是得到每个点到A和B的距离值,然后再对A和B的SDF进行Blend,就会得到我们想要的值,这个就是插值距离函数

演示图片

我们最终融合几何的方式就是先把两个几何通过距离函数得到一些值,然后对这值进行Blend,然后取Blend以后值为0的点就是他们融合的边界

演示图片

水平集

原理跟距离函数的原理是一样的,就是表示方法不一样,他把这些值都放到一堆格子里面,然后取f(x)=0的点出来,就是说这些本来是距离函数算出来的值现在可以用任意函数去算出来一堆值,然后去找出是0的值的形式

演示图片

演示图片

演示图片

显式表示

我们说明的一种显式表示方法如下图,我们使用参数映射的方式来表示几何空间中的点,也就是给你一个(u,v),然后可以得到这个点对应3D空间的中的点,这样就可以直接显式表示出一个几何了

演示图片

同样对于显式来说可以直观的知道现在平面上有哪些点,因为u,v就已经是已知的了,但是对于你想知道这个点是否在几何内外是很难知道的,这个跟隐式是相反的一个特性,这个就是想说明显式和隐式有不同的用法,有适合某种表示方式就是用某一种方式

演示图片

Point Cloud

简单来说就是用一堆足够密的点来表示面,只要点足够密就看起来像是一个完整的几何,一般扫描出来的模型就是一堆原始的点

演示图片

Polygon Mesh

通过三角形或者多边形组成的面或几何,这种是广泛应用于图形学届的一种方式,只要三角形足够细小密就能表示出任意的几何,因为是三角形组成,就会涉及到三角形与三角形的连接等问题

演示图片

下面显示的是一个几何模型文件存储的内容格式,其中是表示一个立方体,这种文件一般有三种基本信息(顶点,法线,纹理坐标),分别对应内容中的 v, vn, vt,然后f就是每个三角形的组成信息,每一项就是对应前面 顶点的下标/纹理的下标/法线的下标,一个f就表示一个三角形的数据,也就是三个点

演示图片

曲线

贝塞尔曲线

定义:这条曲线的起始点和终点必须在p0和p3上,并且切线方向是由p0到p1的方向起始,到p2,p3这个方向结束,就会形成下图中的一条曲线,蓝色

演示图片

贝塞尔曲线的表示有一个算法可以表现出来,就是 德卡斯特里奥算法,该算法如下图中,比如给定一个时间t,这个t是一个从0到1的值,假设现在有三个点b0,b1,b2,我们在从起始点b0开始到b1做一条曲线,做法就是通过b0到b1这个线段上插值得到t在该线段上的点b10,然后再从b1到b2之间插值得到点b11,然后再从b10到b11这个线段上插值得到b20这个点,那这个点就是这个曲线在t时所在的点,如果把t从0到1的点全部以此类推连起来得到的线就是贝塞尔曲线

演示图片

具体算法如下:

演示图片

演示图片

这里是相同的算法,表示四个控制点时的曲线

演示图片

如果用代数的方式表示上面的算法的话,可以用伯恩斯坦多项式的方式去表示,这里暂时略过,还不懂多项式

演示图片

贝塞尔曲线有几个特性,一个是仿射变换后的点形成的贝塞尔和之前的点形成的是一致的,还有一个就是贝塞尔曲线的点一定都在这些控制点所形成的凸包范围内,然后定义就是有一个起始点和结束点,然后起始点和结束点的方向一定

演示图片

凸包 (Convex Hull) 定义:能够包围给定的一定几何形体的最小凸多边形,直观定义就是可以把下图中一堆黑点想象成一个平面上的钉子,然后拿一个可以无限扩张的橡皮筋拉到钉子的最外围然后放开,此时橡皮筋形成的多边形就是凸包

演示图片

逐段贝塞尔曲线

当一个曲线有太多控制点去控制的时候,会出现不太好控制的情况,所以人们法线用一段一段的曲线去连起来会更好的呈现出更复杂的曲线

演示图片

人们更倾向与用四个控制点表示一段曲线,然后再连接起来这些曲线,这个就叫 分段三次(piecewise cubic) 贝塞尔

演示图片

C0连续:两个曲线在几何上的连续点就叫做C0连续,也就是下图中的红圈

演示图片

C1连续:如果是基于切线的连续,中间的点就等于左边的点和右边的点组成线段的中心,不过这个要满足切线连续的情况下,也就是两个点基于水平,而且方向相反,离中心的距离一样,这就叫C1连续,也可以叫一阶导数连续

演示图片

Spline(样条)

一个连续的曲线,由一系列控制点控制的,然后满足n阶连续性

演示图片

B-splines

对贝塞尔曲线的一种扩展,具有局部性,可以支持修改一个点时只会影响一段曲线,简单来说这么理解,具体很复杂,可以自己去了解

演示图片

演示图片

曲面

贝塞尔曲面

一个贝塞尔曲面是有4x4的控制点来得到的,过程如下

演示图片

取四行上的每四个点在时间t下分别做贝塞尔曲线,

演示图片

然后把上面得到的四个控制点再用另一个时间t做贝塞尔曲线得到的点拼在一起就会得到贝塞尔曲面,就是类似于双线性插值的两次贝塞尔曲线,水平一次得到四个点然后再竖直做一次贝塞尔曲线

演示图片

演示图片

我们想得到曲面上的任意一个点就是通过两个不同的时间t,我们可以叫做U,V

演示图片

我们通过输入U,V两个0到1的值就会得到对应的点,就会得到一个几何面,这个就会符合我们之前说的显式几何的规则

演示图片

Mesh

Mesh操作总览:三角形细分,三角形缩减,三角形规则化

演示图片

Mesh Subdivision

Loop Subdivision

简单来说这种细分的流程就是先生成更多的三角形,然后再移动这些顶点的位置

演示图片

拆分就是连接三角形三条边的中点就会形成一个三角形,就会被划分成四个三角形,这样就做到了细分三角形,然后做顶点移动,老的和新的都要分别移动

演示图片

先更新新的顶点的位置,只要不在边界的情况下,这个顶点一定会被多个三角形所共享,比如图中中间的白点被两个三角形所共享,然后我们白点所在把共享边的两个点叫做AB,不共享的叫CD,然后这个点的位置更新就是下面公式,会发现AB的位置加权更多,因为这种算法认为AB离它最近,所以影响更多

演示图片

旧的顶点更新:首先这个顶点的更新要跟他周围的顶点有关,然后我们定义两个值:一个n(顶点的度,就是这个顶点有几天边跟他相连,此处有六条,这个就是6),一个u(这个就是一个跟n有关的值),然后我们的公式就是如下,可以看到我们自己的点加权是(1-n*u),其他点的加权是u,这里的意思就是说当度更多时我们认为要更加的会影响到我们的点的改变,反之小时就更相信我们自己的位置,就是这么一个概念

演示图片

演示图片

Catmull-Clark Subdivision

首先这种细分可以针对不只是三角形的网格,可以是任意多边形,前面的Loop只可以对三角形,然后细分方式跟前面一样,先细分多边形,然后移动顶点位置,在这之前我们先定义一些概念:首先是非四边形,就是不是四边形的多边形,然后是奇异点,就是度不等于4的点,可以看到这张图里面有两个非四边形和两个奇异点,然后下面开始细分

演示图片

细分方式就是取每个多边形的边上的中点和这个多边形面内的中点做连接,就产生以下情况,然后我们得到以下一些特性,每当分完一次以后,我们发现新增的奇异点数量跟细分之前非四边形的数量是一样的,并且细分完以后所有的非四边形面都消失了,如下图,然后再进行细分之后,奇异点数不会增加了

演示图片

演示图片

然后进行点的更新,依然是针对几种不同的点进行更新的方式不同,如下图,分别对面中间的点F,和边的中心点E,和老的顶点V做以下公式的平均即可

演示图片

演示图片

Mesh Simplification

简单理解就是对模型多边形数量的简化,主要是针对性能

演示图片

首先说是应用边塌缩的方式来做到减少多边形的操作,那么去坍塌那些边才能让这个几何形体的轮廓不发生改变呢,这个时候就要用到二次度量误差的概念

演示图片

就是算出我要坍塌得到的那个点跟他关联几个面的二次误差度量,这个二次误差度量就是这个点到原本几个面的距离的平方和,我们希望这个点在坍缩之后对之前的面影响最小,可以先算出每个边跟他周围面的二次度量误差,然后先坍塌误差最小的边,然后我们有个问题就是如果坍塌完以后会有一些边发生改变,二次度量误差也会发生变化,这个时候我们再取第二小的值的时候可能就会不对了,那就要做到先取最小的变坍塌,然后再对被这个边影响到的边进行值的更新,那就可以用一种数据结构,优先队列或者堆来做这个坍塌更新

演示图片

演示图片