Catmull–Clark 细分算法 UV 问题及解法

avatar
花呗借呗前端团队 @蚂蚁集团

在三维计算机图形学中,算法的选择和实现至关重要。本文将详细讨论 Catmull–Clark 细分算法,以及在使用它生成引擎中的球体时遇到的一些 UV mapping 问题及其解决方案。

什么是 Catmull–Clark 细分算法

Catmull–Clark 细分算法是一种常用的表面细分方法。它适用于任何多面体网格模型,能够创建更高质量的曲面。通过迭代运算,Catmull-Clark 细分算法能够逐渐将任意多边形网格模型转化为四边形网格模型,实现从粗糙到平滑的过渡。

来源:https://danielsieger.com/blog/2021/03/27/generating-spheres.html

已知初始面cell(待细分的四边形面) 、顶点坐标position,Catmull-Clark 细分算法的基本步骤如下:

  1. facePoint:对于每一个面,计算其所有顶点坐标的平均值
  2. edgePoint:对于每一条边,计算其两个顶点和与其相邻的所有面点的平均值
  3. 新position:对于每一个原有的顶点,通过计算其相邻所有面点的平均值F、相邻所有边中点的平均值R、原位置P重心坐标得到新的顶点位置:(n为相邻面数)

image.png

  1. 生成新的面:对于每一个面,连接 新position(三角) - 一条边edgePoint(正方体) - facePoint(球体) - 另一条边edgePoint(正方体),将一个面分成四个新的面

来源:https://en.wikipedia.org/wiki/Catmull%E2%80%93Clark_subdivision_surface

为什么选择该算法生成引擎中的球体

Catmull–Clark 细分算法在处理几何表面的细分和平滑过程时,会考虑到相邻的面、边和顶点的信息,因此生成的球体相较于普通的 UV sphere(下方左图) 方法不仅数量级更低,而且其球面更为平滑,定点分布均匀、视觉效果也更好。
image.png

球体 UV Mapping

在生成mesh面后,需要考虑如何将 2D 纹理映射到该球体上。一种通用的方法是使用极坐标系,即
image.png
从而映射至 (-1,1)的范围内,得到

image.png

UV 分布问题以及解决方案

在使用极坐标得到 uv 后,立刻发现纹理沿着纬度方向出现了压缩、球体两极出现了旋转。这两者都是 vertex sharing 造成的。
纹理沿维度方向出现压缩两极出现了纹理旋转

纹理压缩

出现压缩的原因不难分析,从球体顶视图看,uv坐标中u,本该是 0.875 - 1.00的部分,变成了 0.875 - 0.00。
image.png
找到u = 0的顶点不难,但如何定位到被影响的三角面?
image.png
这样的三角面具有一个显著的特征,即以 uv 坐标为顶点构成的三角形,其方向与球体其他三角面不同。即 uv 坐标构成三角面的法向量与其他不同:

    const m1 = indices[i * 3];
    const m2 = indices[i * 3 + 1];
    const m3 = indices[i * 3 + 2];

    A.set(uvs[m1].x, uvs[m1].y, 0);
    B.set(uvs[m2].x, uvs[m2].y, 0);
    C.set(uvs[m3].x, uvs[m3].y, 0);

    // ab side of this triangle
    Vector3.subtract(B, A, AB);
    // ac side of this triangle
    Vector3.subtract(C, A, AC);
    // uv's normal of this triangle
    Vector3.cross(AB, AC, normal);

    // direction reversed triangle
    if (normal.z > 0) {
      ...
    }

纹理旋转

顶点出现纹理旋转的原因是,公用极点的三角面如下图黄色虚线。这个问题并没有一种通用的使用方案,我采用的一种解决方案是,取极点上任意给定三角形的另外两个顶点的U分量的平均值,即蓝色虚线。平均U分量的方法通过在纹理的顶部边缘均匀地排列三角形的尖端,最小化了三角形的内部拉伸。这样在细分步数较少时候仍然可以看到接缝,但是纹理旋转已经消失。
image.png

球体半径

image.png
以上两步结束后,球体极点出现了偏移。打印可知,极点的uv坐标中v不为0。这是因为该算法细分初始值为一个边长为1的正方体,细分后并非球体。因此需要将得到的分布均匀的顶点,重新投影到球体上。即最终顶点位置为该点法向量乘以半径。

对比

与之前球体算法进行比较,面数接近时更圆:
左:768面, step(细分次数) = 3;右:722面,segments = 19
顶视图
顶视图 贴材质

小结

在实践中Catmull-Clark细分算法被广泛用于生成高质量的球体模型。尽管如此,该算法在进行UV映射时会出现一些问题,如图像压缩、旋转图案以及极点中心的偏移。我们提出了针对这些问题的解决策略,包括寻找并替换UV法线相反的三角面,以及校正顶点位置。尽管需要一些额外的计算,但能有效提高球体模型的质量,使其更加真实和可信。

如何联系我们

Galacean 开源社区群 (钉钉):

image.png

Galacean 开源社区群 (微信):

添加群管理员微信:zengxinxin2010, 并备注 “galacean 加群”

网站

官网地址
galacean.antgroup.com
Engine 源码地址
github.com/galacean/en…
Engine Toolkit 源码地址
github.com/galacean/en…