1 曲面细分
曲面细分是指将一个模型的面合理的分成更多小的面,从而提升模型精度,提高渲染效果,让物体更加趋近于真实世界.
三角形越多,模型越精确,产生的视觉效果更直观更好.
a) Loop细分
首先要介绍清楚,这个Loop细分并不是循环细分的意思,而是发明这个算法的人叫Loop.
Shout out to every bald man!
总而言之,Loop细分总体只做了两件事:
-
先细分(将一个三角形变成四个小三角形)
-
再调整个顶点的位置.
具体步骤如下:
1 细分:
通过连接三角形各边中心点,我们可以在一个大的三角形基础上,得到四个新的小三角形.
2 调整:
细分了之后我们要对现如今的各个三角形的顶点位置进行调整,从而产生平滑的过渡效果,显得不会突兀.
对于新老顶点我们要分别用不同的规则来调整:
- 对新顶点:
如图中的白点是通过细分后产生的一个新顶点,它一定在三角形的一条边上,只要这条边不是表示的边界,那么它一定会被不同的三角形所共享,比如图中白点所在的边就被上下两个大三角形所共享.
我们把这条共享边上的两个顶点叫做A 和 B,剩下的两个顶点叫做C 和 D,也就是四个黑点.
找到黑点之后,白点现在的位置就是3/8的(A和B的平均位置) + 1/8的(C+D的平均位置),也就是其位置为周围4个顶点的权重之和:
因为A,B两点离白点近,权值大,C,D两点离得远,权值小.至此我们得到了新顶点的位置.
-
对老顶点:
如图我们可以看到,白点是一个老顶点,他一共被六个大三角形共享,此时白点的位置一部分取决于其他相邻的老顶点,剩下的取决于自己的位置.在此我们要引入两个概念:n和u
n: 顶点的度,连接几条边就是几度,如图白点为6度
u:与度相关的一个数,如果是n = 3,那么y = 3 /16;如果n != 3,则u = 3 / 8n.(如图中白点的u应该是1/16).引入n和u是为了求出老顶点现在的位置:
一方面相信自己原本的位置: (1 - n * u) * 原本的位置
一方面想引自己周围老顶点的平均: u * 老顶点们的位置平均.
将他们一相加就得到老顶点现在的位置.
如果一个顶点连接了很多个三角形,例如连接了20个三角形,那么这时就可以忽略他自己的位置,只需要由周围20个三角形来决定自己的信息.
这是一个不断进行Loop细分的例子效果.
b) Catmull-Clark细分(Catmull-Clark Subdivision)
Loop细分针对是所有三角形面,但是现实中常用的网格不仅仅只有三角形网格,因此就有了Catmull-Clark细分,这里以四边形面和三角面的混合为例:
首先做一些定义:
1 我们定义四边形的面为quad face,对于所有不是四边形的面,称之为Non-quad face
2 所有度不为4的顶点称之为奇异点
(如图中紫色的点即为奇异点,因为这两个点的n为5)
定义完这两个概念之后我们来介绍如何细分的:
1.取non-quad 面中间附近的一个点
2.取non-quad 面上的每条边的中点处
3.将non-quad 面中间的点与边上的中点连接,生成了若干个新的quad face,从而达到了曲面细分的效果.
结果如下图所示:**
我们在经过一次细分之后:
1 有几个非四边形面,就会多出几个奇异点,所以现在一共有2+2 = 4个
2 新多出来的奇异点的度数与原来non-quad face的边数相等,如这里原non-quad face是三角形,新产生的奇异点就是3度
3 如果在第一次细分之后所有面都会变成四边形,不存在non-quad face,那么往后奇异点数目不再增加
如果此时我们再做一次细分,仍然不会增加奇异点:
可以看到奇异点依然是4个,不再改变。
以上我们明白了如何增加新顶点,与Loop细分类似,我们同样需要去调整各类顶点的位置,这里将所有的顶点分为三类:
-
face point
-
edge point
-
Vertex point
对于各类顶点位置调整如下图所示:
Loop细分 V.S Catmull-Clark细分:
曲面简化
曲面简化是指将一个模型的面合理的合成更少的面,从而降低模型精度,为特定情形下提供使用(如LOD技术)
边坍缩
其实曲面简化所利用的一个方法叫做边坍缩,如上图所示就是将一条边的两个顶点合成为一个顶点。
但随之而来的问题就是,曲面简化需要尽量保持原本模型的形状,图中我们坍缩一条边,与之相连的边的也会发生改变,比如原先趋近于竖直的边现在趋近于平行,这些会导致模型的样貌变化.
因此坍缩哪一条边能够使得原模型样貌被改变的程度最小,这是曲面简化的关键所在。
为此我们引入一个度量,即二次误差度量(Quadric Error Metrics)
即坍缩之后蓝色新顶点所在的位置与原来各个平面的垂直距离之和,在此我们忽略如何求新顶点的位置,我们认为新顶点的位置是可求得.
如果能够使得这个二次误差度量值处于最小,那么在进行边坍缩之后,对整个模型样貌修改一定程度上也会较小,因此我们应该最先从这条影响最小的边进行坍缩.
那么其实到这整个曲面简化的算法流程已经比较清晰了:
1.我们对模型上的每条边进行赋值,其值为坍缩这条边之后,代替两个老顶点的新顶点所能得到的最小二次误差度量
2.找到在所有边中二次误差度量最小的那条边做坍缩,新顶点位置为原来计算得出使得二次误差度量最小的位置
3.由于坍缩之后会引起与之相连的一些边的变化,因此要更新这些边的二次误差度量值,在坍缩之后重新计算这些边的二次误差度量并更新.
4.重复2 , 3 步步骤,直到到达终止条件.
这其实是一个标准的贪心算法,可能到不了全局最优解,但事实证明最终的结果依然相当不错
总结:
到此,几何部分就全部结束了,我们了解了显式和隐式几何,明白了贝塞尔曲线和贝塞尔曲面,也知道了曲面细分和简化的做法,下一章我们将进行关于闫老师的Ray Tracing部分,拖延症真的没救了…在好久就将几何部分的笔记写在了本上却一直没有更新电子档,加油,打工人,大家都在进步本来就已经落后于他人了更要勤奋.
“勤奋的人不一定是天才,但天才一定勤奋.”