光照贴图参数化
正如Jon在上一篇文章中所解释的那样,我们在《见证者》中使用了预先计算的全局照明,而我的首要任务之一就是开发该系统。
我开发了一些有趣的技术来计算自动参数化,以一种可以轻松映射到 GPU 的方式制定照明计算,并通过使用辐照度缓存来加速它们以较低频率执行。 这些东西都不是非常前沿的,但我遇到了一些通常在文献中被忽视的有趣问题,并提出了一些我认为值得分享的创造性解决方案。 然而,回想起来,我认为我也犯了一些错误,但我希望诚实地对待这些错误可以帮助我在未来避免这些错误。
在第一篇文章中,我将描述我已经实现的光照贴图参数化算法,在接下来的几篇文章中,我将介绍我们的照明系统的其他细节,例如我们使用半立方体执行最终聚集的方法以及我们的辐照度缓存的实现。
为了使用预先计算的照明,我们需要一种将这些照明计算映射到表面的方法。 一种可能性是按顶点存储它们,但在许多情况下,这不能提供足够的分辨率,并且照明的插值使网格的三角剖分相当明显。 许多游戏通过用高纹理和法线贴图细节来补偿光照细节的缺乏来解决这个问题,但这与Jon想要实现的图形风格不太相符。 因此,我们决定创建对象的完整参数化,以便将预先计算的光照存储到光照贴图纹理中。
手动创建这些参数化是可能的,但这很耗时,我宁愿让我们的艺术家做一些更有趣的事情。 因此,我们决定自动创建参数化。 然而,迄今为止我所犯的最大错误是没有更仔细地研究实现这一目标的可用解决方案。 我已经有了一些实现的部分,并且我高估了将它们组合在一起并产生可靠结果所需的工作量。 在与 GDC 的一些朋友谈论此事时,其中一位问我为什么不使用微软的 UVAtlas 工具,令我沮丧和尴尬的是,我唯一的答案是我没有想到这一点。 我认为这证明了在像我们这样的小团队中对我们的发展持开放态度是多么有价值。
现在我已经解决了这个问题,让我们谈谈技术。 我们仅使用光照贴图来表示间接照明和静态区域灯的直接照明。 因此,我们的期望是光照贴图将相当平滑,并且接缝不会成为大问题。 因此,我们决定不投资保证无缝参数化的解决方案,而是使用相当传统的方法:我们首先将输入几何图形划分为具有磁盘拓扑的图表,单独对它们进行参数化,最后将它们打包到矩形纹理中。
1、分割
将网格划分为图表(charts)是迄今为止该过程中最复杂的步骤。 过去我尝试过使用层次聚类,但没有取得太大成功,所以这一次我决定使用类似于 Lloyd 算法的迭代聚类算法,与多图表几何图像 (MCGI) 论文中使用的算法相同。
与 Lloyd 的聚类算法一样,MCGI 算法在图表增长和重新播种阶段之间进行迭代。 图表的增长由基于法线偏差和面质心之间的距离的度量引导。 在每次图表增长迭代之后,都会选择图表最中心面的新种子,并重复该过程,直到种子位置不再改变。
我的 MCGI 算法实现效果还算不错,但并不总能产生良好的结果。 可以调整种子的数量和位置以获得所需的输出,但这需要一定量的用户干预,而这是不希望的。
部分问题在于,在这种情况下“好”的含义非常主观。 它通常意味着形状优美的图表,非常适合表面,产生几乎没有失真的参数化,具有相当直和凸的边界,并且大小大致相等。
为了使算法适应我们的目的,我做了两件事,修改了引导方法,以便自动选择初始种子数量,并使用指标组合来更好地控制结果。
为了选择初始种子数量,我只需将种子一一插入,并增长相应的图表,直到满足阈值。 此时,我选择一个尚未分配给任何图表的任意面并重复该过程。 当没有面留下时,所有种子并行地重新开始生长过程。
消除对初始条件的敏感性的常见策略是使用最远点启发式。 然而,我没有这样做,而是发现一种行之有效的方法是从已选择的图表中挑选最差的候选面孔作为下一个种子。
该算法的第二个重要变化是使用一组不同的指标。 MCGI 论文提出了一种将法向偏差与面部质心之间的距离结合起来的度量。 我发现使用绝对距离使得算法非常依赖于网格的镶嵌,并且测量距质心的距离有利于具有低纵横比的三角形。
我没有使用面之间的距离,而是只考虑了法线偏差,并将其与类似于 D 图表中提出的其他指标相结合:准可开发网格分割,并且考虑了圆度和直线度。
这些指标也有自己的问题,我必须以各种方式调整它们。 最重要的问题是它们以不受欢迎的方式限制了图表的增长。 例如,为了鼓励图表凸性,你可以将高因子与相应的度量相关联,但这会导致大量几乎凸的图表,一旦发现凸配置,就无法将其他面添加到图表中。 因此,我不使用这些指标来限制增长,而是仅使用它们来支持凸图或直线边界; 这使得图表可以自由生长,但仍然保留尽可能最凸和最直的形状。
在许多情况下有帮助的技巧是吸收艺术家的一些意见,但不会给他们带来任何额外的负担。 一种简单的方法是考虑网格的现有参数化。 我们的对象已经具有用于纹理的参数化,并且艺术家倾向于将纹理接缝放置在不容易看到的位置。 将图表的边界与现有的接缝对齐不仅减少了接缝的总数,而且还导致图表以更好地匹配艺术家手动完成的方式演变。
我独立考虑了纹理和正常接缝。 由于我们的参数化用于照明,因此我更严格地遵循法线接缝并与其角度成比例,不这样做会导致拐角显得不太明确或更模糊。 这也有助于该过程在具有许多硬边缘的架构网格中更快地收敛。
最后,我没有施加任何图表拓扑限制。 我特别希望只要指标低于所需的阈值,图表就会围绕网格中的孔生长。 我很想使用更好的代理拟合指标而不是正常偏差指标,但这会生成必须切割的圆柱形或圆锥形图表,而我不想处理这个问题。 关闭另一侧的洞相当容易,只需检测边界并关闭所有边界,但最长的一个。
2、参数化
对于图表参数化算法,我们只需使用最小二乘保形映射,因为我已经有一个可用的实现。 我的实现基于 SIGGRAPH 2007 网格参数化课程笔记中的算法描述,我发现它比原始论文中的更容易理解。 特别有用的是关于数值优化的章节,尽管如果我必须再次编写一个稀疏矩阵求解器,我可能会使用 OpenNL,因为它现在已经在自由 BSD 许可证下发布。
LSCM 并不是最好的参数化算法。 它在大多数情况下工作得很好,尽管在一些罕见的情况下它会导致小的自我重叠。 这发生在两种情况下:
- 输入中的零面积三角形有时会在参数化中翻转。
- 具有复杂边界的图表,在参数化时会自相交。
第一种情况是由输入网格中的 T 形接头引起的,这些 T 形接头被检测为孔并填充有退化三角形。 在实践中,参数化中的小重叠并不是真正的问题,因此我们不修复输入,而是计划将这些问题报告给导出器中的美工人员,并让他修复它们(如果事实证明这会导致伪影)。
在第二种情况下,增加聚类过程中使用的凸性度量的权重使我们能够防止这些错误。 所以,我并没有真正采取任何措施来解决这个问题,但到目前为止这还不是一个问题。
即使在那之后,我们仍然存在一些有问题的案例。 我注意到 Blender 中的实现没有遇到同样的问题,并且可以更优雅地处理这些情况。 因此,我询问了 Brecht Van Lommel,他建议使用基于 LSCM 的 ABF 公式的替代矩阵权重,这似乎消除了剩余的问题。
虽然 LSCM 非常容易实现,但它绝对不是最好的参数化方法。 如果我要实现更好的东西,我可能会考虑 LinABF 或拟合引导梯度场。 然而,由于单个图表的参数化是目前最快的步骤,因此考虑更昂贵的变形分析方法可能是有意义的。
3、打包
我们的打包(packing)算法相当简单。 与许多其他实现一样,我们首先按参数区域对图表进行排序,旋转它们以将图表与其最适合的矩形对齐,然后将它们一一引入到图集中。 理想情况下,我应该测试所有 4 个可能的方向,但目前我只是随机选择其中一个方向。
我没有使用类似俄罗斯方块的方案来找到每个图表的最佳位置,而是使用了一种更强力的方法,其中考虑了所有可能的位置。 我使用保守的光栅化器来实现这一点,该光栅化器标记图表所触及的所有纹素,再加上一个用于填充的额外纹素。 随着新图表的插入,我逐渐增加纹理范围。 如果找到当前范围内的位置,则自动接受图表,否则将评估度量以确定增加地图集范围最少的位置。 由于我使用贪婪算法,最小化面积会导致地图集具有非常高的纵横比。 因此,我反而最小化了结合范围和周长的度量,并产生了大部分方形地图集。
以下是一些结果示例:
一旦我们使用光照贴图压缩,将图表与 DXT 块边界对齐以防止渗色伪影可能是有意义的。
4、未来的改进
这是我认为有很大改进空间的领域之一,但与此同时,花费更多时间来改进结果并没有太多!。 尽管尚未在生产中进行测试,但我认为我们当前的解决方案运行得相当好。 如果有更大的图表,失真更少或接缝数量更少,那就太好了,我肯定会很乐意做这件事。 然而,这并不会让游戏运行得更快或者看起来更好。 我们计划在某个时候发布这些算法的源代码,所以我希望随着其他人采用它并改进它以满足他们的需求,实现会逐渐变得更好。
也就是说,如果我认为有一个领域值得投资,那就是信号专用参数化的使用。 关于该主题的研究论文(信号专用参数化和分段线性重建的信号专用参数化)在我们的设置中可能有点过分了,而且我不确定它们是否能很好地处理我们的低分辨率网格。
《半条命 2》通过使用艺术家为每个表面指定的采样率来实现这一点,但我认为使用类似于 Bungie 提出的方法自动实现这一点是值得的,该方法看起来相当简单,并且提供了更复杂的方法所获得的大部分收益给我们。
我的期望是,除了一些小的调整和轻微的调整以处理将来可能出现的问题案例之外,当前的实施不会发生重大变化。 如果有人对此类算法有任何经验,我很想听听。 我特别想知道你是否会采取不同的做法,或者是否有任何我可能忽略的优化或改进,而你认为值得考虑。
原文链接:Lightmap Parameterization
BimAnt翻译整理,转载请标明出处