在这篇技术博客中,我们要介绍如何大幅度优化静态环境,这使我们能够把成本高昂的像素用在最有效果的地方,也就是场景中的交互式物体和近景物体。这听起来也许很微不足道,但是在实践中常常会与我们工作室的创新和迭代工作流程冲突,而我们假设其他许多工作室也会遇到同样的问题。我们将解释我们的优化理念,以及我们如何依靠UE4中的工具创建高度优化的环境内容而不限制创作精彩体验所需的工作流程。我们在这篇博客中将以《Time Stall》作为主要案例,但是这些优化有许多已经在我们的其他作品中实现,包括《National Geographic:Explore VR》(Oculus Quest)、《Coaster Combat》和《Pet Lab》(Oculus Go)。
(本视频转载自YouTube:视频原址)
我们工作室的使命就是挑战人们眼中VR的极限。我们致力于在可靠的技术基础上实现高品质的视觉效果。为了达成这些雄心勃勃的目标,我们定义了一套内部的优化理念,它建立在下列原则的基础上:- 优化工作必须尽可能自动化。
- 优化工作必须是非破坏性的,要为美术和迭代留出自由。
- 优化是我们工作流程的一部分。我们努力在项目的早期实现高性能,通过经常的自动化测试验证,并致力于保持。
大家应该早就知道,VR优化的主要焦点包括下列几项。对于移动VR来说也是一样;只不过预算会稍微紧张一点。
- 着色器复杂性:我们要绘制许多像素,有时还要多次绘制,所以只要有可能,就应该降低它们的成本。
- 绘图调用计数:更改状态的成本在GPU和CPU上都很高。要限制更改次数(我们在Quest上定的目标是150次左右)。
- 三角形计数:原始顶点数据是一个限制因素,在移动VR上尤其突出。我们把目标定在150000左右。
在《Landfall》开发期间,我们就开始寻找优化静态场景的方法。很快,我们就发现了虚幻引擎中提供的层级细节水平(HLOD)系统。它可以对多个物体一起执行批处理来减少绘图调用,还可以将多个材质烘焙到一个新的材质中。这听起来完全符合我们想通过优化工作流程改进来实现的目标。
这里是《Time Stall》中的一个HLOD集群示例,展示了能够获得多少性能。
HLOD过程通常包含两个阶段:- 生成集群
- 将场景中的Actor组织到一起,形成一个代理模型的过程。
- 这个过程可以手动执行,也可以自动执行。
- 我们在自动化集群生成中更改了不少东西,将在下文重点讲述。
- 构建代理模型
- 合并要用于渲染代理模型的源模型(和材质)的过程。
- 合并后的模型会在各个方面得到优化:
- 多个模型合并为一个,减少绘图调用次数。
- 材质合并。减少材质数量并简化它们。
代理模型和材质切换示例。
橙色:HLOD级别2。Actor数量:1
蓝色:HLOD级别1。Actor数量:2
绿色:HLOD级别0。Actor数量:8
HLOD系统中的选项为所有想用它进行优化的人提供了一个很好的起点。但是在我们的作品开发过程中,我们又不断改进和扩展了HLOD系统,使它能够达成以上所有效果,但又以更高的质量产出更好更快的结果。在下面几节中,我们将说明我们对这一过程所做的更改以及原因。
橙色:HLOD级别2。Actor数量:1
蓝色:HLOD级别1。Actor数量:2
绿色:HLOD级别0。Actor数量:8
改进的自动化集群生成
集群生成是HLOD过程的第一步。在这里,系统会选择要以集群方式组成代理模型的静态网格体Actor。起初我们的美术团队是手工执行所有集群操作的,这是出于三个原因。首先,自动执行集群操作会产生意外或不理想的结果。其次,我们发现创建集群是相当缓慢的过程,很费时间。最后,我们认为用来控制集群的参数数量太有限。比如在默认情况下无法区分不同类型的材质着色器模型,这会导致透明和带遮罩的材质被当作不透明材质烘焙。随着时间推移,我们对集群系统做了下列改进。
- 通过实现一种替代集群算法提高集群生成速度(如果有人想知道,我们选择了层级凝聚聚类)。
- 添加了集群约束来加强对组成集群的材质类型的控制。
- 集群约束可以是材质类型,甚至可以是材质的静态开关值。
- 添加了更多集群生成选项。
添加了可视性剔除
我们所做的较大改进之一就是提供了移除玩家绝对看不到的网格体三角形的功能。在游戏中,我们定义了一个游玩空间,将玩家约束在该空间中。游玩空间是用一个或多个体积乃至贯穿关卡的样条表示的。在创建HLOD资源期间,工具将会移除所有从游玩空间绝对看不到的三角形。
上图:《Timestall》中在三角形剔除前的餐厅场景。
下图:同一个场景,已剔除不可见的三角形。
改进了图谱方法
在材质合并期间,纹理会被放进纹理图谱中。默认情况下,HLOD系统使用一种基于网格的解决方法。每个打包的资源可以获得不同的分辨率,但这取决于资源的纹理大小。我们注意到,有时候系统会对背景中使用的某些物体分配许多纹理空间,那是因为它们的材质中刚好有一种任何类型的大纹理。使用大纹理贴图可能出于多种原因:多种资源被组合在一个大纹理贴图中,或者某种在设计中贴近游玩空间的道具也被用在背景中。在上述任何一种情况中,资源都会在组合的图谱中获得许多空间。我们用于三角形剔除的体积为我们提供了更好地将图谱打包的功能。这里列出我们对图谱方面做的改进。
- 在执行过三角形剔除之后创建图谱
- 重新生成UV以实现最佳打包
- 靠近游玩空间的物体与距离较远的物体相比,有更大的分辨率
- 定义打包纹理中物体的大小时,还考虑了光照贴图分辨率
左边是虚幻引擎的默认网格布局。在图谱纹理中,每个网格体都分配到一块正方形的区域。
右边是我们加权的UV图谱布局。
材质烘焙扩展
我们对材质合并过程做的另一个更改是提供更多将纹理烘焙到图谱的选项。系统提供了烘焙和组合纹理的功能,但是仅限于PBR工作流程。将最终输出烘焙到一个纹理中是不可能的。我们实现了一套系统,允许美术师控制将哪些内容烘焙到最终纹理中。- 烘焙底色
- 默认UE4烘焙方法
- 仅将底色输入组合到新生成的纹理中
- 保留PBR着色
- 使用此选项通常还会烘焙一个组合的法线贴图,以及打包的金属感、粗糙度和环境光遮蔽贴图
- 主要用于贴近游玩空间、仍然需要动态着色的物体
- 烘焙漫反射
- 将光照贴图和底色烘焙到一个纹理贴图中
- 烘焙漫反射和高光度
- 将光照贴图、底色和所有着色烘焙到一个纹理贴图中。这对于远处的物体非常有用。
- 烘焙高光度着色的位置由场景中的Actor决定
- 结果是一个可以放在无光照材质中的纹理贴图。这是成本最低的渲染方式
- 烘焙漫反射、高光度和雾
- 与前一个选项相同,但是还包括指数高度雾
左边HLOD级别为0。它使用原始的PBR材质。各个网格体合并为一个新的网格体,剔除了不可见的三角形。这一LOD级别仅当玩家站在靠近它的地方时才显示。
中间:HLOD级别1。这个网格体有一个非常简单的材质,其中所有光照和着色都已烘焙到纹理中。
右边:HLOD级别2。与HLOD级别1相似,它有一个简单的材质,其中只有一个纹理贴图输入。所有光照和着色都已烘焙在其中。
自从我们开始根据自己的特定需求扩展HLOD系统,已经过去两年多。这给了我们足够的时间评估结果的优劣,以及对开发过程的影响。
从好的方面来说,它几乎实现了我们最初的所有目标:
- 这个过程是非破坏性的,因为可以根据原始设置(重新)生成新的内容。进行调整时,通常只需要再次运行HLOD过程。
- 这一过程能在虚幻基本代码(例如编辑器和commandlet)中运行,这带来许多优点。它与在编辑器中设置的各种属性都能很好地集成。此外,我们可以改变现有代码的用途,并利用和扩展现有的代码路径。
- 它几乎是全自动的过程,这真是太棒了。
将来有几点需要注意:
- 应用程序足迹会增加,有时候很明显。把“所有东西”都烘焙到一组HLOD中能带来性能奇迹,因为我们只要渲染一个漫反射纹理即可。但是,所有这些资源都会得到各自独特烘焙的纹理图谱。因此要注意你的软件包大小和加载时间。
- 目前,它还需要初始手工设置;这主要是按项目进行的配置。还需要一些初始资源,才能让这些设置发挥作用。
- 最后可能也是最主要的缺点,就是我们必须控制更改数量。《堡垒之夜》带来了对HLOD系统的许多改进,有时与我们自己的优化冲突。因为这是UE4中的核心系统,所以它伴有许多更改成本,几乎在每次引擎升级时,我们都必须合并我们自己的更改。
虚幻引擎是一种用起来令人惊叹的引擎,而且多亏了开源许可证,我们能够对引擎进行调整来使它适应我们的需求!
我们也一直在物色能够帮助我们构建更好的UE4体验的人才。如果你愿意在阿姆斯特丹工作,和我们一起制作有挑战性的VR和AR作品,请看一下我们的工作机会。
前面已经提到过,这里为想要针对Oculus Quest优化的开发者提供一些参考材料:
- UE4 Performance and Profiling | Unreal Dev Day Montreal 2017 [2017年10月9日]
- Optimizing Oculus Go for Performance [2018年3月22日]
- One Mesh To Rule Them All [2018年4月3日]
- Tech Note:Profiling & Optimizing on Mobile Devices [2018年5月30日]
- OC5 Talk - Porting Your App to Oculus Quest [2018年9月26日]
- Oculus Connect 5 | Reinforcing Mobile Performance with RenderDoc [2018年9月26日]
- Understanding Gameplay Latency for Oculus Quest, Oculus Go and Gear VR [2019年4月]
- Developer Perspective:UE4 Logging and Console Commands for Mobile VR [2019年7月2日]
- Developer Perspective:Improving Memory Usage and Load Times in UE4 [2019年7月25日]
- Developer Insights:How to Develop with Vulkan for Mobile VR Rendering [2019年8月2日]
- Common Rendering Mistakes:How to Find Them and How to Fix Them [2019年8月22日]
- Official Oculus documentation on Rendering in Unreal Engine 4 [2019年9月4日]
- Official Unreal Engine 4 documentation on HLOD [2019年9月4日]
- OC6 Talk - Using Vulkan for Mobile VR [2019年9月26日]