曲面
- 隐式曲面的特点
所谓隐式曲面指的是并不会告诉你任何点的信息,只会告诉你该曲面上所有点满足的关系。来举个具体的隐式曲面的例子
相信读者都能一眼看出来这是一个3维球体的方程,一般地的我们会把隐式曲面的代数方程写作 f(x,y,z) = 0,该球体的 f(x,y,z) = x^2 + y2+z2-1
对于隐式方程来说因为没有给出任何点的信息,因此如何采样到曲面上具体的点是一个很难的问题,如下图这样一个例子
如果使用隐式曲面方程,将会十分容易的判断出一点与曲面的关系,这是一种非常具有吸引力的特性(能够轻易的判定光线与物体是否相交)
- 显式曲面的特点
对于显式曲面来说是与隐式曲面相对应的,所有曲面的点被直接给出,或者可以通过映射关系直接得到,如下图
区别隐式曲面与显示曲面的关键就在于是否可以直接表示出所有的点
隐式曲面难以采样曲面上的点,但是可以轻易判断点与曲面的关系,对于显式曲面来说恰恰相反,我们可以很轻易的采样到所有的点,但是给予你任意一点却很难判断它与曲面的关系
因此没有哪一种的几何表现方式是更好的,根据具体的任务来选择隐式还是显式才是合理的做法
隐式曲面
单纯代数表达式的曲面都颇具有规则性
Constructive Solid Geometry(CSG)
CSG指的是可以对各种不同的几何做布尔运算,如并,交,差
符号距离函数
除了对于几何的布尔操作,还可以通过距离函数来得到几何形体混合的效果
首先对于符号距离函数来说本质上就是一种定义距离的函数。如有空间任意一点到各个几何物体表面的距离,对这些距离做各种各样的运算操作最后得到的一个函数就是最终的距离函数了
对于这样一个二维平面的例子,定义空间中每一个点的SDF为该点到阴影区域右边界的垂直距离,在阴影内部为负,外部为正,因此对于A和B两种阴影来说的SDF分别如上图下半部分所示。有了SDF(A),SDF(B)之后对这两个距离函数选择性的做一些运算得到最终的距离函数,这里采用最简单的SDF = SDF(A)+SDF(B)来举例,最终得到的SDF为零的点的集合即为blend之后曲面,对该例子来说,就是两道阴影之间中点的一条线
因此对于一开始的那个例子来说,只需合理定义空间中任意一个点的SDF,再令SDF为0即可得到混合的效果了
对于几何体混合效果自然不可能像这里简单的两个距离相加就可以得到了,该效果具体实现是找出任一个点到两个几何体表面距离中的最短距离再减去一个变量作为该点最终的SDF
水平集
水平集的方法其实与SDF很像(像是SDF的一种特殊形式),也是找出函数值为0的地方作为曲线,但不像SDF会空间中的每一个点有一种严格的数学定义,而是对空间用一个个格子去近似一个函数
对该面内的每一个点利用已经定义好的格子值进行双线性插值,就可以得到任意一点的函数值,找出所有=0的点作为曲面
该方法的好处是对于SDF,我们可以更加显示的区空间曲线的形状。该方法广泛的运用在医学成像和物理模拟之中
分型几何
分型几何是指许许多多自相似的形体最终所组成的几何形状。
如雪花是一个六边形,放大之后会发现每一个边上又是一个六边形,再放大六边形边上的六边形边上又是六边形,就这样无限套娃,有点递归的意思
隐式曲面具有形式简单,轻易判断点与曲面关系等优点,但难以采样曲面点和模拟过于复杂的形状
显式曲面
点云
就是很多很多的点构成的曲面,直接有着所有点的信息,没什么太多可讲的,多过点多模型细节就多,点少模型细节就少
多边形网格
对于多边形网格来说相信读者并不陌生,该方法广泛应用在计算机图形当中,简单来说通过定义各个多边形面的顶点以及顶点之间的连接关系就可以得到许许多多的三角形面或是四边形面,再通过这些面来近似表现出我们想要的模型效果
比较著名的.obj文件,一个立方体的模型数据例子
3-10行定义了立方体的8个顶点信息。
12-25行定义了这些顶点的纹理坐标信息(每个面4个点,共6个面所以最多有24种不同的纹理坐标信息,这里有一些纹理对于不同面上的点是公用的)。
27-34行定义了6个面的法线信息,为什么有8个是因为建模软件输出的精度问题不必在意,其中有两个是重复的。
最重要的就是36-47行了,f 代表一个面,其中x/x/x的第一位表示是哪个顶点,第二位表示该顶点纹理坐标是第几个,第三位表示法线信息是第几个。 3个 x/x/x表示3个顶点的信息构成一个面
贝塞尔曲线与贝塞尔曲面
贝塞尔曲线
其中 p 0 , p 1 , p 2 , p 3为控制点,蓝色所表示曲线正是非常著名的贝塞尔曲线了,可以从图中观察到,曲线会与初始与终止端点相切,并且经过起点p 0与终点p 3。
其实贝塞尔曲线的定义很像参数方程,给定一个参数t∈[0,1]就能确定贝塞尔曲线上的一点,倘若取完所有t值,就能得到完整的贝塞尔曲线,了解一下大概之后,接下来我们就开始介绍计算曲线的过程。
n个控制点得到的是n-1次曲线,如图中3个控制点便是2次贝塞尔曲线
如此便成功获得了如图所示的3个控制点之下的2次贝塞尔曲线上的一点 b0^2了,那么对所有的 t∈[0,1]都重复上述的过程,就可以得到上图所示的蓝色贝塞尔曲线了。通过这样一个简单的3个控制点的例子,相信很快就能理解贝塞尔曲线的原理,那么对于4个控制点,5个控制点,乃至任意控制点步骤都是类似的
其核心所在就是多次的线性插值,并在生成的新的顶点所连接构成的线段之上递归的执行这个过程,直到得到最后一个顶点
4个控制顶点的例子
那么我们为何称由n个控制点的贝塞尔曲线为n-1次呢?同样以一开始的3个控制点为例,将贝塞尔曲线方程完全展开看看
其实看到这就已经非常清楚了,最终得到的贝塞尔曲线方程恰好就是一个关于参数 t 的二次方程,如果细心观察的话,其实可以发现控制点的系数是非常有规律的,很像二项系数,因此可以总结规律得到一个任意控制点组成的贝塞尔曲线的方程如下
回想一下PS等具有画图功能的软件中的钢笔工具所运用的便是贝塞尔曲线了,除了这个例子之外许多字体或是矢量图都广泛运用了贝塞尔曲线。但对于高阶贝塞尔曲线它有一个严重的缺陷
对于上图所示的由11个控制点所得到的10次贝塞尔曲线,由于控制点众多,很难控制局部的贝塞尔曲线形状,因此为了解决该问题,有人提出了分段贝塞尔曲线,即将一条高次曲线分成多条低次曲线的拼接,其中用的最多的便是用很多的3次曲线来拼接,如下图
如果想要使得拼接的点看起来较为光滑的话,就要满足一些连续条件如一阶连续(连接点导数的左右极限相等),二阶连续等等
除了贝塞尔曲线之外还有B样条曲线,NURBS曲线等等
B样条曲线相对于贝塞尔曲线可以更好的进行局部控制
NURBS曲线可以得到一些B样条曲线无法精准描述的圆锥曲线
贝塞尔曲面
其实在理解了贝塞尔曲线之后,贝塞尔曲面的原理也是十分容易理解的了,无非是一个从2维到3维的过渡
首先规定一共4x4 = 16个控制点,其水平面位置如图中16个黑点所示(并未表示出高度,防止图形太乱),将这16个点分成4列,图中红色圈中的为一列的具体例子。
第1步 在这4个控制点之下利用第一个参数 u uu 运用第一章的计算贝塞尔曲线的方法得到蓝色点,因为有4列,所以一共可以得到如图所示的4个蓝色点。(灰色曲线分别为每列4个点所对应的贝塞尔曲线)
第2步 在得到4个蓝色顶点之后,在这四个蓝色顶点的基础之下利用第二个参数 v vv 便可以成功得出贝塞尔曲面上的正确一点
第3步 遍历所有的 u,v值就可以成功得到一个贝塞尔曲面
曲面细分与曲面简化
曲面细分是指将一个模型的面合理的分成更多小的面,从而提升模型精度,提高渲染效果
曲面简化是指将一个模型的面合理的合成更少的面,从而降低模型精度,为特定情形下提供使用(如LOD技术)
当然除了细分与简化之外,还有另外一种同属一类的操作叫做曲面规则化(Mesh Regularization)其所作的便是将三角面都变的尽可能相同,从而也达到提升模型效果的目的,这里不做详解
曲面细分
Loop细分
Loop细分是一种专门针对三角形面的细分方法
-
生成更多三角形或顶点
如图所示在,连接每条边的中点生成一个新的三角形,原来的三角形就会被分割成4个三角形 -
调整这些三角形或顶点的位置
我们将所有的顶点分为两类,一类是新生成的顶点,一类是老的原来就有的顶点,对于新生成的顶点做如下处理
这里新的顶点就是白色的那个顶点,其位置为周围4个顶点的权重之和,各顶点权重如图所示,其余边上的新顶点处理类似
对于旧的顶点,做如下处理
其实旧每个顶点的处理也十分类似,这里以图中一个白色旧顶点为例,也是其自身以及邻接顶点的权重和,但权重的设置与该旧顶点度数有关,具体如图中右下部分所示。
以上就是Loop细分的全过程了,最后看看效果
Catmull-Clark细分
正如上文所说Loop细分针对是所有三角形面,那么对于不仅仅只有三角形面该怎么办呢?这也就有了Catmull-Clark细分,这里以四边形面和三角面的混合为例
以上我们明白了如何增加新顶点,与Loop细分类似,同样需要去调整各类顶点的位置,这里将所有的顶点分为三类,对于各类顶点位置调整如下图所示
图中对于3类顶点每次细分之后新的位置讲述的已经很清楚了,明白过程大概即可。
曲面简化
其实曲面简化所利用的一个方法叫做边坍缩,如上图所示就是将一条边的两个顶点合成为一个顶点。但随之而来的问题就是,曲面简化需要尽量保持原本模型的shape,如何坍缩一条边,或者说坍缩哪一条边能够使得原模型样貌被改变的程度最小,这就是曲面简化的关键所在
为此引入一个度量,即二次误差度量
即坍缩之后蓝色新顶点所在的位置与原来各个平面的垂直距离之和。如果能够使得这个误差最小那么对整个模型样貌修改一定程度上也会较小
这其实是一个标准的贪心算法,可能到不了全局最优解,但事实证明最终的结果依然相当不错