【GAMES101]图形学学习记录——几何
【GAMES101]图形学学习记录——几何
在现实生活中,物体有各种各样的形状,在这一节中,我们将学习如何在图形学中表示这些不同的形状。
隐式和显式几何表示
隐式几何表示
只包含构成几何形状的点满足的关系,不包含这些点的具体位置,通常为一个函数。例如一个球的隐式表示:
通常用以下方式表示:
隐式表示很容易判断一个点在不在几何平面上,但很难找出几何平面上有哪些点。
显式几何表示
直接将几何形状上的所有的点都表示出来,或者通过参数映射的方法定义的表面。参数映射的解释如下:
显式表示很容易判断哪些点在平面上,但很难判断一个点在平面上,平面内还是平面外。
不同的隐式表示
之前所说函数形式的隐式表示虽然能表示出一个几何图形,但我们很难直观地通过一个复杂的函数知道这个几何图形的形状。以下是一些其他的隐式表示方法。
- CSG(Constructive Solid Geometry):通过对基础的几何体做一些简单的布尔运算来表示复杂的几何体。如图所示:
- Distance Functions(距离函数):对于任何一个几何图形,不直接描述它的表面,而是描述如何一个点到这个表面的最近距离。求出两个物体的距离函数,并进行融合,就可以得到新的物体。(怎么感觉更不直观了
不同的显式表示
点云:不考虑物体是一个表面,而是表面上的一些点,当足够精细时就和平面相差无几。
多边形面:大多数是三角形和四边形。用多边形的组合来描述几何图形。在图形学中的应用最为广泛。
.obj文件:一种文本文件,分别记录了一堆点,一堆法线和一堆纹理坐标,再将它们组织起来来描述图形。
曲线(Curves)
贝塞尔曲线
用一系列控制点去定义某一个曲线。
算法
假设在时间0-1内,时间0在起始点,时间1在结束点,我们要算出在任意时间0-1中任意时刻点在空间中的位置。对于n个控制点(n>2),我们在每两个相邻的点之间连一条线段,并在这个线段上找到使其比例为t的点。当进行一轮这样的操作后,我们得到了n-1个点。重复以上操作,直到最终只剩下一个点,这个点就是时间t所在的点。当我们枚举时间t,得到的点连成的就是贝塞尔曲线。图解如下:
性质
- 贝塞尔曲线的起点是第一个控制点,终点是最后一个控制点。
- 起点处切线的方向一定为b2-b1,终点处的方向一定为bn-b(n-1)。
- 控制点经过仿射变换后,生成的贝塞尔曲线形状不会改变。
- 控制点得到的曲线一定在控制点形成的凸包内。
逐段控制的贝塞尔曲线
当控制点过多时,计算成本会增加,同时控制的效果会变差。因此,更高效的做法是逐段用少量控制点(通常是四个)来逐段控制曲线。
B-splines(B样条)
样条是一种完全可控的曲线,而B样条是贝塞尔曲线的延伸,它具有局部性,在改动控制点时影响的范围有限。
曲面
贝塞尔曲面
贝塞尔曲面是由贝塞尔曲线得到的。原理和双线性插值基本相同,我们在两个方向上分别应用贝塞尔曲线即可。
三角形的细分和简化
三角形的细分
有的时候,三角形数量不足会导致模型不够精细,这时候,我们希望能增加三角形的数量来提升模型的精细度。细分通常分为两步:将一个三角形分成多个三角形,之后调整这些三角形的位置使其符合模型。
Loop细分(Loop Subdivision)
将三角形三边的中点连起来,就得到了四个小的三角形。以前的顶点称为旧的顶点,中点称为新的顶点。
对于新的顶点,如果它被两个三角形共享,则它的位置由这两个三角形的旧的顶点加权得出。和它在同一条线段上的两个顶点的权值是3/8,另外两个顶点的权值是1/8。如图所示:
对于旧的顶点,定义n为顶点的度,定义u为和n有关的数,当n=3时,u=3/16,否则u=3/(8n)。旧的顶点的位置有自己和周围的点加权得出,如图所示:
Catmull-Clark细分
Loop细分只能对三角形做细分,而Catmull-Clark细分在一般的情况下也能进行操作。
定义非四边形为所有边数不为4的多边形,奇异点为度不等于4的点。对所有的边都取中点,所有的面也取中心点,将中点和中心点连起来就产生了更多的多边形。当进行这样一次操作后,奇异点的数量增加了非四边形的数量,所有非四边形都消失,并且之后不会再有奇异点的增加和非四边形的出现。效果如下:
每个点位置的更新方式如下图所示:
三角形的简化
有的时候(例如当物体离摄像机很远的时候),物体的精细程度并不十分重要,在这种情况下,我们希望用更少的三角形来表示物体,以达到减少性能消耗的目的。
边坍缩(Edge Collapse)
想象有一条边,当我们捏住它的两个顶点并重叠到一起,这条边就不复存在了。这就是边坍缩的概念。但是对于一个物体来说,我们怎么知道哪些边不重要,可以进行坍缩,哪些不能呢?这里需要用到二次误差度量的概念。二次误差度量是指顶点到到和它相邻的所有平面的距离的平方和。
在进行边坍缩时,优先坍缩二次误差度量最小的边即可。但是,当我们对一条边进行坍缩后,和它相邻的边会受到影响,导致二次误差度量受到影响,这使得我们无法先计算所有边的二次误差度量,再依次进行坍缩。在这里,我们可以用最小堆的数据结构进行计算。