介绍我们系列中有关在Unity中使用3D模型的第四篇文章。 先前的文章: “在Unity中使用Mesh的功能” , “ Unity:Mesh的过程编辑” , “将3D模型导入Unity和陷阱” 。在上一篇文章中,我们提到了在给定的纹理分辨率下检查纹理扫描是否足够的像素压痕。 在本出版物中,我们通过观察像素压痕及其跟踪算法来描述问题的实质。 它不会被认为是代码,而只是可以在任何语言和任何开发环境中实现的原理。

发行
订购3D模型通常伴随着纹理分辨率的要求。 由于光栅图像的离散性,3D艺术家必须观察纹理扫描各部分之间以像素为单位的压痕。 缺少必要的缩进会导致以下事实:当不需要像素时,相同像素会在模型上的完全不同的位置显示。
在工作的早期阶段跟踪足够的压痕尤其重要。 大多数情况下,有些人从事几何图形的创建,包括纹理扫描,而其他人则从事绘制纹理的工作。 3D美术师检测到的错误所造成的麻烦要少于纹理设计人员所发现的错误。 在后一种情况下,如果使用的3D包不提供用于绘制几何图形的工具(例如画笔),情况将变得更加复杂。
您还应该考虑两个细微差别,因此,扫描元素之间可能需要更多空间。 首先是在mipmapping期间纹理分辨率降低。 第二个是在形成
光照贴图时使用
膨胀滤镜 。 在创建
UV扫描的任务期间,需要以3D艺术家的纹理分辨率要求为指导,并且还要考虑到上面列出的细微差别。 但是,如果没有自动验证,就根本无法注意到许多缺点。
细节减少的工件外观示例对于简单模型,可以使用自动工具生成纹理扫描。 但是,它们基于内部指标,没有考虑像素缩进,因此共享像素通常沿对角线边界放置。 使用棋盘格纹理进行检查不会显示所有错误,此外,这些纹理通常比项目中将使用的分辨率更高。
共享像素UV扫描中像素压痕不足的问题类似于重叠问题。 在这两种情况下,都可能发生所谓的
出血 -在
上一篇文章中,我们描述了这会产生什么假象。
但是,像素缩进的问题取决于最低纹理分辨率要求。 一次检查就足以确定覆盖层,而纹理分辨率的要求可能会在开发的下一阶段发生变化。 由于我们使用的3D软件包没有用于自动检测与
UV扫描的各个部分的邻近性有关的错误的工具,因此情况变得复杂。 并且不要忘记在
Unity中使用自动成型器后
,您仍然需要检查
UV2 。
我们决定创建一个可以检查像素缩进并标记模型中潜在间隙位置的工具。 缩进要求将基于以下参数确定:
- 纹理的基本分辨率。
- 不允许流动的纹理的最低分辨率。
- 最小纹理上所需的缩进。
由于我们使用的纹理大小等于2度,因此以基本分辨率计算必要的压痕的公式非常简单:(基本分辨率/最小分辨率)* MinTexture上的压痕。
显然,解决该问题的方法与栅格化密切相关。 为了更清楚地说明算法的要求和开发,我们介绍了几个概念。
关键概念
考虑一个
UV空间和一个尺寸为NxM的均匀网格,范围在0.0-1.0之间。 1 / N宽和1 / M高的单元格形成一个
UV空间的分区。
NxM分割UV空间我们取两个任意点,并将Dn表示为连接给定点的线段的U轴上的投影所占据的像素数。 同样,Dm为V轴,然后我们将
像素距离定义为Dn和Dm之间的最大值。
像素距离应该注意的是,在欧几里德空间中,如果以
像素距离为度量标准,则平行平移和旋转等运动并不是网格的运动。 这种细微差别使我们解决方案的开发有些复杂。

我们将边为K像素的正方形称为K的
核心。 这样,
像素距离小于K的任意两个点都可以被K的核覆盖。
不同尺寸的磁芯示例如果多边形的两个边缘的中点(四个顶点处的质心)位于沿顺时针方向围绕轮廓的边缘的左侧,则多边形的两个边缘会形成
轮廓的
凹面 。 对于逆时针遍历,条件是在边缘右侧找到一个点。
一对肋形成轮廓的凹陷解决方案
现在让我们直接谈谈检查像素缩进。 为了实现它,我们提出了一个由三个独立片段组成的算法。 执行顺序并不重要。 每个片段的结果是NxM矩阵,它是分区单元格的缓冲区,其中标记了某些单元格。 这三个缓冲区的总和是一般结果。
首先,考虑最简单的代码段。 归结为找到相交于退化的三角形和边缘的细胞,这些三角形和边缘的长度小于给定大小的原子核的侧面。 所有此类单元格都在缓冲区中标记。
检查元件尺寸的结果在描述其他两个片段之前,请考虑其工作的一般逻辑。 两者都与称为
壳或岛的三角形簇的处理有关。 3D美术师的外壳是一组相连的多边形,也就是说,该组中的每个多边形都有一个相邻的多边形,该多边形与之共享公共顶点。 另外,壳牌是一个独立的训练场。 此外,对于贝壳,岛屿和集群,我们指的是同一件事。

要查找所有壳,我们对图的所有连接组件使用搜索算法,其中图的顶点由多边形表示,边缘由一对多边形中存在的公共顶点表示。 由于
Unity中唯一的多边形是由顶点索引定义的三角形,因此,如果第一个顶点的至少一个索引与第二个顶点的任何索引相同,则我们认为这些三角形是相邻的。 从与图的相似性和确定边缘的方法可以得出,一个聚类的顶点的索引集不与另一个聚类的顶点集相交。

共同部分完成。 我们将考虑的第二个片段确定与不同聚类的邻近或重叠相关的潜在错误的位置。
许多簇以
UV空间中三角形集的形式馈入输入,
UV拆分的尺寸对应于纹理的分辨率(NxM),压痕值P作为像素数。 对于给定的分区,必须找到簇之间的像素距离小于所需缩进量的区域。 如果结果矩阵中的一个单元格进入至少一个与两个不同簇相交
的值K = P + 1的核心,则该单元格将被标记。
片段的本质几乎在结果描述中列出。 有必要找到所有壳中与三角形相交的
K大小的核 ,然后在结果缓冲区中标记这些核的单元。
在我们的实现中,依次考虑所有成对的集群。 对于每一对,确定这些簇覆盖
的大小为K的
内核集的交集区域。 选择一个对,并将其表示为Q。

然后,必须通过以下标准检查Q的所有元素:给定内核在所选对的每个簇中是否与至少一个三角形相交。 如果是这样,则标记已测试内核的所有单元。

所有集群对都带有标记单元的缓冲区构成结果。
集群缩进结果现在,我们将处理最后一个片段。 在这里,您需要处理一个集群。 输入是
UV空间中的一组三角形,对应于纹理分辨率(NxM)的
UV分区的尺寸以及作为像素数的压痕值P。 可以在两种情况下标记一个像元:聚类无效或有孔,或者凹面边缘之间的像素距离小于所需的凹痕。
群集的内部对我们不感兴趣-首先,我们将获得由连接的边列表表示的轮廓。 相邻的三角形重复了顶点的索引,因此,如果该簇顶点的一对索引唯一,则该边缘属于轮廓。 确定了哪些边缘形成轮廓后,有必要对其进行组合,以便获得链表。
如果在此步骤之后,轮廓的所有边缘都没有进入列表,则说明该簇有孔,或者网格数据中存在错误。 在这种情况下,需要适当地标记与簇相交的核的所有细胞。
如果找到轮廓,则处理继续。 我们制定了以下结果要求。 让形成
轮廓凹面的那对边
与K = P +1的
核相交。 然后,如果边缘之间的轮廓的两个部分都超出该细胞核,则必须标记细胞核。
集群功能测试结果我们决定通过轮廓边缘的成对比较来实现这一要求。 我们从凹度条件开始,然后对于每一对,检查与两条边相交的所有内核。 为了测试内核,需要在一对边之间遍历轮廓的每个部分。 如果每个部分都包含至少一个超出原子核边界的点,那么将标记该原子核的所有细胞。
标记已检查内核的单元格的条件总结
上面的算法非常适合使用并行计算的实现。 每对簇和边缘的处理独立发生。 由于检查是基于栅格化的,因此,如果您不是从成对的边缘开始而是以核心开始处理,则建议使用
GPU的功能。
我们将算法的结果转换为纹理。 对于给定的分辨率,这使您可以以图形方式显示
UV扫描中潜在缺陷的位置。 同样,可以将生成的纹理应用于模型以直接在几何图形上看到标记。
在以下示例中,我们使用
Blender自动工具专门切割了兔子和Suzanne,以便获得更多工件。 检查的纹理分辨率为256x256,所需的缩进为1。
蓝色封面标记的单元格中有孔,三角形和边缘太小。 绿色表示具有每个簇特征的细胞核。 未观察到簇之间缩进的内核以红色标记。
在下一篇文章中,我们将考虑一种通过消除不可见几何图形来优化场景中3D模型的算法。 和我们在一起!