查看原文
其他

程序丨在虚幻引擎4中,光照贴图UV坐标如何快速生成?

2017-09-06 崔嘉艺 Gad-腾讯游戏开发者平台

译者:崔嘉艺(milan21)

审校:王磊(未来的未来)


概要


在虚幻引擎4中,为静态网格生成光照贴图的UV坐标是项目烘焙时间和启动时间的重要组成部分,至少直到引擎针对平台特化后的资源版本数据(DDC)被填充之前都是如此。这主要是由于那些用于UV封装的算法和方法造成的。这种方法主要是在艺术家创建美术资源没有创建光照贴图的的时候提供一个备份(当然,他们可以提供一个更好的版本!)。所以当我们必须自动化完成这些工作的时候,我们不希望这些自动化工作会吃掉很多时间。在UE 4.16版本发布以后,它在光照贴图生成速度方面取得了重大的进展 - 但是在今天的博客文章中,我们将向你展示我们可以做进一步的提升,我们能够让总体性能提升近5倍。


你可以在以下Github Pull请求中看到我们的更改:github.com/EpicGames/UnrealEngine/pull/3686。


目前,引擎使用一个线性搜索来找到第一个匹配,然后跟着用二分搜索,以查看是否可以改进提高 - 增加UV大小并测试以查看新的大小是否仍然适用。


4.15 – 逐像素处理


这是在UE 4.15版本中针对Epic的Boy with Kite demo (KiteDemo)生成的各种DDC(引擎针对平台特化后的资源版本数据)资源所做的统计数据输出 – 高亮了StaticMesh部分,这是总花费时间里面非常重要的一个部分:


DDC(引擎针对平台特化后的资源版本数据)资源的统计数据:


(点击图片,可放大查看)


以下是几个重要网格的细分以后的结果:


(点击图片,可放大查看)


你可以从上面的统计数据中清楚地看到,为复杂的静态网格找到最好的UV封装花费了大量时间。


找到最佳封装的过程包括两个步骤 - 缩放(具有连续UV坐标的三角形组)和封装。 为了封装,引擎将对三角形组(以矩形纹理表示)进行8个定向测试,并选择最佳的方向,以便尽可能创建密集的封装。



对于每个方向测试,这个算法使用的是软件光栅化方法,从左上到右下填充矩形纹理并扫描,以确定是否有足够的空白来容纳这个三角形组。方向测试使用的是基于2D碰撞检测的极其昂贵的方法。当我们处理更大的光照贴图的时候,这个开销将变得更加昂贵。


举个简单的例子来说,一个1024×1024的布局纹理和一个16×16的矩形纹理,我们最终可能会对每个方向做(1024 - 16)x(1024-16)x 16 x 16次的碰撞测试来得到结果。此外,对于每个测试,还有一个检查过程(一次64位),对于复杂的网格,可以有数千个单独的三角形组。对于添加进来的每个附加组,所有以前拟合的组必须重新定向,所以算法变得越来越慢,因为我们的数组的索引一直在增长。


4.16 – 对段进行处理


以下是UE 4.16版本的计时数据,强调下Epic实现了对选择的优化,并对其进行了改进:


DDC(引擎针对平台特化后的资源版本数据)资源的统计数据:


(点击图片,可放大查看)


这个数据结构带来的主要好处在于,它不是逐像素地扫描布局纹理,现在引擎可以对段进行处理。由于一行中段的数量通常远低于该行中像素的数量,所以循环迭代的次数可以显着的降低,特别是对于高分辨率纹理来说更是如此。


在UE 4.16版本中,Epic已经创建了一个新的数据结构来表示2D纹理。因此,每个纹理包含几行,而每一行都有使用的段和空闲的段(一段是指同一行中的一些连续像素)。


如上所述,每个三角形组由一个矩形纹理所表示,而每个矩形纹理由八个唯一的通过旋转操作或是镜像操作而彼此相关的部分来表示。UE 4.16版本中的三角形封装系统的另一个优化是把三角形组的四个旋转方向光栅化,然后这四个光栅化的三角形组被镜像,以获得剩下的四个。这样做的结果就是,光栅化时间可以减少4倍,但是由于三角形组的光栅化是非常快速的过程,因此总的增益相对较低。


这里有一些从KiteDemo中获取的网格细分的结果:


(点击图片,可放大查看)


从上述结果可以看出,三角形组的封装所需的时间已经显着的减少,特别是ScotsPine_01。然而,对其他两个网格的改进并不是那么好。 这是因为这些网格的细节需要大量的小三角形组,导致每行有大量的段,所以优化效果较差。


4.16 – 分段+优化


在UE 4.16版本中,FLayoutUV:: FindBestPacking()方法会遍历线性搜索方法,直到找到最佳拟合大小,然后执行最多六次二进制搜索迭代,每个迭代都应该会对最佳拟合比例(UVScalePass)有提高 。二进制搜索完成后,使用UVScalePass作为参数来生成最终的封装结果,有效地重复调用了最后二进制搜索迭代中执行的函数。我们已经缓存了FindBestPacking()的结果以及UVScalePass。因此,可以避免重复的三角形组封装操作。我们还添加了一个检查,以查看最终的二分搜索是否成功,如果成功的话,则可以省略最终的三角形组封装步骤。该方法可以将FindBestPacking()函数所需的总时间减少约10%,具体减少多少取决于执行线性搜索和二分搜索的次数。


我们实现的第二个主要优化是FLayoutUV :: PackCharts()方法中的异步执行。不再是每个测试都对每一个三角形组进行八个方向测试,而是将每个测试都放在一个允许并行执行的任务图(用于短时间运行的任务)里面。由于所有测试都在同一时间运行,并且每个任务图都无法访问其他任务的结果, 4.16版本引入的优化之一已被移除 - 因为这个优化与异步操作不兼容。这是一个检查,用来检查当前方向所得到的测试结果是否比以前测试得到的最好结果要好。如果是这种情况的话,那么特定的迭代将被提前终止。我们还必须放弃在4.16版本中引入的另一个优化,这个优化将拟合操作做了更改,最开始的尝试是在三角形组的最后一个失败的行上找到最佳匹配,而不是从头(左上角)开始,因为从头开始的话会实际上让我们的算法慢一些。


执行上述优化以后在UE 4.16(KiteDemo)版本中的计时结果:


DDC(引擎针对平台特化后的资源版本数据)资源的统计数据:


(点击图片,可放大查看)


再次对网格进行细分得到了如下的结果:


(点击图片,可放大查看)


结论


这是KiteDemo项目烘焙总时间的最后比较,以突出三种不同方法的表现:


(点击图片,可放大查看)


另外,每个算法生成的光照贴图UV坐标的缩放有时可能略有不同。这可能是由于每个三角形组的封装偏差差异或是浮点计算带来的舍入误差。无论如何,所有这三种方法都可以提供密集的光照贴图UV坐标,而不会出现重叠。


从这些测试结果可以看出,4.16版本的分段方法比4.15版本的逐像素方法效果更好,特别是在具有高纹理分辨率和低三角形组数量的网格上。对于其他网格,如果包含了更多的三角形组,改进并不是很明显 – 这主要是由于段的数量比较多。我们提出的异步执行方法在这些网格(例如具有超过9000个图表的HillTree_02)上运行良好,因为每个三角形组的八个方向测试可以并行执行,从而达到八倍的速度增益。


在默认情况下,在KiteDemo网格上未启用分段方法,但是重新保存这些网格应该会导致关卡加载速度的显著提高。用户可以通过在详细面板 - >构建设置中取消选中生成光照贴图UV坐标复选框来重新保存内容,重新选中该复选框并保存内容。如果是从源代码中构建引擎的话,可以将以下行添加到PackCharts()函数的开头的地方:



这样就可以强制引擎使用分段方法来进行封装了。


【版权声明】

原文作者未做权利声明,视为共享知识产权进入公共领域,自动获得授权。


----------------------

今日推荐


如何加快Unity3D游戏的冷启动时间?

Unity渲染基础系列教程(九):复杂材质

虚幻引擎的内存分析功能:Malloc Profiler 2 介绍



添加小编微信,可享双重福利

1.加入GAD程序猿交流基地

获取行业干货资讯,观看大牛分享直播

2.领取60G独家程序资料库,地址在小编朋友圈

包括腾讯内部分享、文章教程、视频教程等全套资料

 

↓长按添加小编GAD苏苏↓

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存