超硬核技术分析:P社新大作《城市天际线2》如何“因性能而大败”?

【GameLook专稿,未经授权不得转载!】

GameLook报道/每每遇到因优化翻车的游戏佳作,GameLook都会默默感到惋惜。

光在今年的PC市场,我们就已经见证了多起这样的事件:《最后生还者重制版》、《卧龙》、《星球大战绝地:幸存者》……这些玩法上较为上乘的作品,却因为糟糕的帧率和卡顿等问题在Steam等平台获得海量差评。

如果说游戏的底层玩法一般难以改动,优化问题大多都是可以通过延长开发和修缮的时间来解决的“低级问题”。而在发行商的死线和资金要求等重重因素之下,不少原本优秀的游戏却不得不以不完整的形态与玩家见面,进而让口碑受到严重影响,功亏一篑。

而在近期,最令人感到可惜的案例无疑是《城市天际线2》了。作为PC平台最热门的城市建造类游戏之一,《城市天际线》吸引来了大量粉丝,续作更是受到万众瞩目。然而预购了的忠实粉丝们发现,哪怕自己拥有一块性能不错的显卡,游戏依然会出现严重卡顿,甚至在菜单界面的帧率就已经不足20帧了。

随后,大量的差评如期而至。有Reddit网友通过反编译发现,游戏之所以会出现卡顿,很可能是因为游戏渲染了NPC小人的高精度模型,甚至连满口的牙齿都细致地进行了渲染。在模拟类游戏中往往会同屏出现大量的小人,这种失误无疑会给显卡带来重大的性能负担。

受到这名Reddit网友的启发,一名来自芬兰的程序员Paavo Huhtala决心进一步深挖《城市天际线2》背后的程序设计。与《城市天际线2》的开发商Colossal Order同为芬兰人,又是一名模拟游戏的忠实粉丝,Paavo Huhtala在工作之余花了近两周的时间对这款游戏进行了深入挖掘,足以说明爱有多深。随着认识的不断深入,他的反编译研究逐渐积累成了一篇长达万字的博文,对渲染的各个通道进行了一一拆解,足够我们彻底了解翻车的症结所在。

尽管GameLook并非游戏技术专业人士,但在洋洋洒洒万言中凝结的爱与投入也难免让GameLook受到触动。在Paavo Huhtala看来,《城市天际线2》的失误绝非开发者“摆烂”造成的,事实上,开发者们对于打造优秀画质有着很高的追求,并试图引入实验性的功能进行实现,但最终也因这些功能的不完善而在优化上惨烈翻车。

而紧迫的预算和死线,更是让这款产品不得不“早产”。一款翻车的产品背后没有赢家——开发者们的愿景没有得到实现,发行商损失了可观的收入,而玩家们更失去了一款本应十分优秀的游戏。

GameLook对Paavo Huhtala的博文进行了全文编译:

作为今年最受期待的PC游戏之一,《城市:天际线2》于上周发布,但玩家反响不一。我的印象是,游戏玩法和模拟似乎是朝着正确的方向迈出的一步,至少从纸面上看,这款游戏的功能似乎比原作时更加完善。然而,这款游戏也存在一些重大问题,包括平衡问题、有瑕疵的设计选择以及导致许多游戏经济模拟上几乎毫无意义的漏洞。这款游戏是否能成为原作的优秀继任者仍是一个悬而未决的问题,但有一件事几乎是普遍认同的,那就是《城市:天际线2》的性能表现完全不达标

这不是一篇性能评测

实际上,事前早就出现了危险信号。在游戏发售前一个月,游戏方就发布了一份公告,告知游戏的推荐系统要求已经提高,且主机版本发布被推迟2024年。不少主播和创作者获得了游戏的早期体验权,但他们被明确禁止谈论游戏性能表现。这种情况并不罕见,因为游戏往往会在发行前的最后几周进行频繁的性能优化和其他修复,但这也不是一个好兆头。就在发行前一周,Colossal Order发布了一份声明,我将其理解为游戏的糟糕表现打预防针。然后游戏就发行了。

像《城市天际线》这样的模拟游戏很多难以良好的帧率运行,但《城市:天际线2》的突出之处在于,在大多数情况下,这款游戏都受到了GPU的制约——这对于这类游戏来说很不寻常,因为大多数这类游戏对CPU的要求都很高比如最初的《城市:天际线》,但对显卡的要求相对较低。从视觉上看,这款游戏在大多数方面都比2015年的原版有所改进,但并不比光追版的《赛博朋克2077》更难运行。

就我个人而言,我甚至认为《城市:天际线2》看起来很不好看。虽然单个模型更加细致,比例感令人印象深刻,但阴影表现显然是最后一代的,整个屏幕被渲染工件和过滤不良的纹理所覆盖。将游戏的图像与相对接近的竞争对手《纪元1800》(发行于2019年)完全讨不到便宜。《纪元1800》的观感更加风格化,在我看来,它看起来更加精致和统一,同时即使在2019年被认为是中低端的硬件上也能提供不错的性能。

我不会浪费时间去仔细地测试游戏,因为许多人已经这么做了,而且他们的评测标准比我高得多。我将总结目前的测试结果:当设置调到最低限度以上“非常低”的图像预设,并完全禁用了阴影和雾等高消耗元素时,你需要一个价值1000到2000欧元的显卡才能以每秒60帧、1080p的规格运行游戏。

相比之下,与《城市:天际线2》在同一周发布《心灵杀手2》被认为是这一代主机游戏中最好看的游戏,如果你把所有设置都拉满包括光线追踪、原生1440p或4K DLSS,它的配置要求和《城市:天际线2》差不多。我认为这很好地说明了《城市:天际线2》的要求是多么恐怖。

以下是我的一些个人经历当我第一次在我的高配游戏PC配备NVidia RTX 3080显卡,AMD Ryzen 7 5800X CPU和5120×1440超宽显示器上启动游戏时,我看到主菜单中的帧率低于10FPS。在调整了设置包括禁用景深、动态模糊和体积效果之后,我的FPS达到了将近90。特别奇怪的是,这个菜单只有一个静态的背景图像和几个按钮。加载到一个空白的地图时,帧率大约为30到40 FPS,在玩了大约一个小时后,帧率始终保持在这个水平,偶尔会出现掉帧。让我们进一步调查。

拉开窗帘

《城市:天际线2》和它的前一样是在Unity中制作的,这意味着游戏可以很容易地使用任何.Net反编译器进行反编译和检查。我使用的是Jetbrains,它有一个不错的类似于Visual Studio的UI,有大量的搜索和分析选项。然而,静态分析并不能真正告诉我们任何有关游戏渲染性能的具体信息。为了分析渲染过程,我使用了RenderDoc,这是一个开源图形调试器,它为我节省了成本。

让我们来看看这个游戏的一些基础技术内容。《城市天际线2》使用的是Unity 2022.3.7,在撰写本文时才发布几个月。Unity 2022最引人注目的方面是DOTS (多线程式数据导向型技术堆栈技术的稳定,这是Unity已经研究了好几年的技术有趣的是,《城市天际线2》似乎大量运用了DOTS,包括新推出的ECS 技术和Burst编译器。

我已经对Bevy引擎感兴趣好几年了,并且尝试进行了一些实现,如果不是因为这款游戏中的许多问题,我宁愿写一篇“ECS是这类游戏的理想架构”的博文。《城市天际线2》似乎将DOTS发挥到了极致,因为这款游戏比前作更有效地利用了多个CPU内核。不幸的是,许多与图像相关的问题都是游戏使用DOTS间接引起的。稍后我将对此展开讨论。

游戏还利用了很多第三方中间件和一些自定义/Fork下来的库。与DOTS不同的是,Unity的UI Toolkit显然还没有准备好投入生产,因为《城市天际线2》在UI上使用的是Coherent LabsGameface,它是基于HTML、CSS和JavaScript的。简单看一下JS包就会发现他们使用的是React,而捆绑使用的是Webpack。虽然这肯定会让原生开发的纯粹主义者朝天大叫,但我认为至少从理论上,这种模式将使游戏的UI比以前更容易维护和修改。其他值得注意的捆绑库包括InstaLOD,Odin Serializer和英伟达DLSS 3的DLL文件,尽管该技术目前不受游戏支持。

对于图形渲染,游戏使用Direct3D 11和Unity的HDRP。Unity的常规渲染系统只适用于传统的基于MonoBehaviour的游戏对象,所以使用DOTS和ECS构建的游戏需要用一些其它东西来弥补。Unity有一个名为Entities Graphics的包,但令人惊讶的是,《Cities: Skylines 2》似乎并没有使用这个包。原因可能是它相对不成熟,支持的渲染特性有限

根据这个包的技术文档,皮肤用于动画模型,如角色和遮挡遮蔽不渲染其他事物背后的东西)功能都被标记为实验性的,虚拟纹理使GPU纹理处理更复杂,但更高)功能则根本不支持。相反,似乎Colossal Order决定利用BatchRendererGroupUnity的和许多相对底层的代码来自主实现ECS和渲染器之间的粘合。稍后我将更详细地介绍这一点及其许多含义。

连接问题

将Renderdoc连接到进程并收集渲染事件通常是相当琐碎的。通常你只需要向Renderdoc提供可执行文件的路径,工作目录和一些命令行参数,然后Renderdoc启动二进制文件并将自己注入游戏进程。然而,我的问题是,我的游戏是在Xbox game Pass上运行的,这个版本使用了一些奇怪的沙盒和/或NTFS所有权手法来限制你对游戏文件的操作。由此RenderDoc不允许读取游戏的可执行文件,即便作为管理员运行也是如此。在找出Game Pass问题之前,我也尝试使用Nsight Graphics英伟达的(类似于NVidia版本的RenderDoc工具,但它也有同样的问题。最终我用信用卡解决了这个问题:我在Steam上以全价再次购买了游戏,尽管我知道它存在严重的问题。对不起。

然而,Steam版本也不是一开始就顺利运行。这一次的问题是Paradox启动器,这是一个用于大多数Paradox发行的3A游戏的臃肿软件。启动器的二进制文件也包含在Game Pass版本中,但至少在发布时它似乎完全未被使用。基本上来说,当你从Steam启动《城市天际线2》时,它会弹出Paradox启动器,你点击Resume或Play,然后它就会运行游戏的二进制文件。

我试图通过直接运行Cities2.exe来连接Renderdoc,但这不起作用——它创建了游戏窗口,但随后运行了几秒钟,打开启动器,然后退出。在Renderdoc中有一个名为“捕获子进程”的选项,理论上应该使Renderdoc将自己注入到目标进程启动的所有进程中——所以它应该将自己附加到由游戏二进制启动的启动器上,然后再次注入到游戏二进制中——但我认为有一些额外的间接层不幸地阻止了它工作。

我还尝试了很多种其他的方法。最终,我终于通过使用RenderDoc的Global Process Hook选项来把它连接到游戏里。事实上,RenderDoc默认隐藏这个选项并建议不要使用,因为这是一种非常具有侵入性的Hook方法,因为它会将DLL注入到系统上启动的每个进程中,但是,起码它跑起来我们终于可以看到游戏中发生了什么。

后来我也能成功跑通了英伟达的 Nsight Graphics。我没有尝试启动游戏或启动器,而是从Nsight打开Steam,然后像往常一样从Steam的UI启动游戏。但是Nsight种获得的信息并不比Renderdoc更多,因为似乎许多Nsight的分析和性能重点功能不支持D3D11。

Renderdoc分析

首先我要承认,我不是一个专业的图形程序员,甚至不是一个特别精通的业余爱好者。我偶尔会做图像编程,也花了很多时间摆弄游戏引擎,但我在这两方面都不是专家。我从来没有实现过像延迟渲染或级联阴影映射这样的高级功能,尽管我想我知道它们在理论上如何工作的。所以我接下来要说的一些事情有可能是错的。如果你认为我错了,请告诉我

让我们从分析以下的实例帧开始:

这是一个相当复杂的帧,但它远未达到游戏的实际规模。这是在一个大约有1000名居民的小镇上,存档进度大概是进入新游戏后一小时之内。有雨,而且是晚上,但在我的经验中,这两种情况对性能都没有太大影响。游戏版本为1.0.11f1,因此包含了第一个发布后的热修复程序。应该注意的是,在撰写本文时发布了最新的补丁1.0.12f1,它包含了对我将要描述的问题的一些改进,但还远远没有解决所有问题。

Renderdoc报告说,帧渲染大约需要87.8毫秒,平均约为11.4 FPS。游戏当时的平均帧率是30-40 FPS,所以要么这帧是一个异常值正如我们从Gamer Nexus视频中了解到的那样,讽刺的是这是相当普遍的,要么更有可能是RenderDoc在某种程度上增加了一点性能消耗,影响了测量,因为我捕获的所有帧都比我在游戏中正常玩时看到的帧数要高一些。我假设即使Renderdoc确实增加了一些消耗,它也不会以一种完全使测量无效的方式添加它,比如使特定的API调用比通常情况下花费10倍的时间。

以下是我从RenderDoc中获取的一部分数据。

仅从这些数字我们无法推断出什么。6705个渲染命令和超过50000个API调用听起来都很多,但如果没有进一步的情景,它们的成本很难评估。6.7 gb的显存对于这样一个相对简单的场景来说是很多的,特别是考虑到目前仍然有只有8gb VRAM的中低端显卡。

因为游戏使用HDRP,所以它的文档可以用来理解游戏在每帧上执行的不同渲染和计算传递的。我不打算深入研究图像有多华丽,但我会一步一步地介绍大部分渲染过程,并强调其中一些更有趣的东西。

DOTS实例数据

游戏中几乎所有的渲染命令都使用了实例化,这在这种规模的游戏中是必需的。为了进行实例化,游戏有一个大的实例数据缓冲区,其中包含渲染所有对象所需要的一切。每个实例数据的内容和大小因实体类型而异,但似乎建筑等普通游戏对象每个实例大约需要50个,道路则更多。我还没有完全弄清楚缓冲区是如何管理的,因为它是一个非常复杂的系统,但基本上每个可见对象的实例数据每帧都会更新到缓冲区,然后将更改上传到GPU。缓冲区从大约60兆字节开始,并在必要时重新分配到更大的大小。

缓冲区几乎用于游戏的每个渲染命令,根据Renderdoc,它至少在每个顶点和像素Shader中可用,尽管我认为它主要只用于顶点着色器。了解这个缓冲区如何影响GPU的缓存将是很有趣的,因为我假设实例不是按照它们呈现的相同顺序排列在缓冲区中,这可能是缓存的一个问题,但我没有足够的专业知识来弄清楚。无论如何,从这个缓冲区中查找每个顶点的数据都有一定的成本,这可能解释了一些关于高多边形网格的问题,我将针对这一点继续说明

模拟

几个计算着色器用于图形相关的模拟,如水,雪和粒子,以及骨骼动画。这些总共花费1.5毫秒,不到帧时间的2%。

一些早期的猜测认为,游戏的性能表现之所以如此糟糕,是因为它可能将大量实际游戏模拟工作转移到GPU上,节省了CPU时间,但减少了渲染的处理能力。然而,在查询了反编译代码和GPU调用情况后,我可以得出结论,事实并非如此。

虚拟纹理缓存

还记得我提到过实体图形不支持虚拟纹理吗好吧,似乎《城市天际线2》实现了自己的虚拟纹理/纹理流系统。我一开始认为这款游戏使用了Unity的内置解决方案,但在传统的Unity模式下,尽管它在2020年被收购后被添加到引擎中,但它仍然是实验性的,不受支持。

什么是虚拟纹理?我的理解是,虚拟纹理是一种加载和管理纹理数据的方法,比传统的每个纹理资产使用一个GPU纹理的方法更具内存效率。纹理存储在纹理图集中,这基本上是更花哨的版本精灵贴图集由固定大小的贴图组成,每个贴图可以包含一个或多个纹理。节省内存的技巧是,大的纹理可以分成多个贴图,所以如果你有一个大的纹理,只在屏幕的一小部分可见,你只需要加载实际可见的贴图。虚拟纹理可见性信息是在稍后的通道中作为正常渲染的副产品产生的,并且可见性信息用于CPU端来确定哪些贴图需要加载,哪些可以卸载。如果你想进一步了解,虚幻引擎的文档似乎提供了更详细的技术描述。除了地形外,游戏似乎对所有静态3D物体都使用了虚拟纹理。

在我的实例帧的渲染中使用的贴图地图集之一。大规模缩减了尺寸,原始尺寸为16368×8448。

这种纹理方法在理论上是相当优雅的,但它伴随着许多权衡,并且游戏的执行仍然存在一些初期问题,例如高分辨率纹理有时无法加载,即使表面已经十分靠近相机了。虚拟纹理的使用也可能是游戏缺乏对各向异性纹理过滤支持的罪魁祸首,各向异性纹理过滤是千禧年以来PC游戏的标准功能。

天空盒的生成

游戏使用Unity HDRP内置的天空系统,所以它每帧生成一个天空盒纹理一个立方体贴图。这大约需要0.65毫秒,这与其他内容相比并不算多,但如果游戏的目标是60 FPS,那么它将占总帧时间预算的4%。

Pre-pass

来自Renderdoc的截图,显示了我的示例帧的正常/粗糙度缓冲。

现在我们开始实际的渲染。《城市:天际线2》使用延迟渲染,这基本上意味着渲染是在许多阶段完成的,并使用几个不同的中间渲染目标。第一阶段是预通,它每像素深度,法线和平滑信息分成了两个单独的纹理。

这个过程非常耗能,因为它需要大约8.2毫秒来生成,这就是游戏渲染开始出现最大问题的地方。但首先我们需要谈谈牙齿。

牙齿之争

关于《城市:天际线2》的表现,一个奇怪而流行的观点是,角色模型有完整的牙齿模型,尽管在游戏中根本没有办法看到它们,除非我们使用照片模式并将相机剪切到角色的头部。Reddit用户Hexcoder0使用NVidia Nsight Graphics进行了一些挖掘,并将他们的发现发布在Reddit上这也启发了我自己进行研究并撰写这篇毫无意义的长篇文章。据透露,游戏角色不仅有完整的牙齿模型,而且它们一直以最高质量渲染。更重要的是,与角色相关的所有内容都是如此所有角色网格都没有任何LOD。Colossal Order很快就公开承认了这一点,他们甚至提到了LOD处理中其它的问题

Colossal Order还告诉我们,他们正在使用名为Didimo Popul8的中间件来生成角色模型。如果我没记错的话,关于牙齿的争论甚至在游戏发布之前就开始了,当时有人注意到Didimo角色规范中包含了牙齿和睫毛等单独的网格。我最初认为游戏是使用Didimo的默认角色网格——因为老实说,他们看起来非常普通和没有灵魂但现在我不那么确定了。

游戏中的网格实际上比Didimo的默认网格有更多的多边形例如臭名昭著的嘴/牙齿模型由6108个顶点组成,远远超过默认网格的1060个顶点。甚至在我们添加头发,衣服和配饰之前,一个角色大约有56000个顶点,这是很多的。就环境而言,在添加庭院道具和其他细节之前,平均低密度住宅建筑使用的顶点少于1万个。

在这个示例帧中,游戏渲染了13组牙齿,它们对帧的视觉影响为零:没有一个像素受到影响。即使是角色本身,除了噪音和伪影,对画面也几乎没有贡献。

过度未优化的角色模型并不是游戏表现不佳的唯一原因因为问题从来都不是那么简单,但它们指向了是游戏在资产和渲染方面的更广泛的问题。游戏经常使用太多多边形绘制太多对象,但对最终图像几乎没有影响。这并不是特定于预通阶段,因为同样的问题似乎会影响所有栅格化几何图形的渲染通道。我认为这主要有两个原因

  • 有些模型根本没有任何LOD变体。
  • 游戏的筛选系统不是很先进自定义渲染代码只实现了截锥体遮蔽,完全没有遮挡遮蔽的迹象。有一些基于距离的遮蔽,但不是很激进,这对于避免画面闪烁很好,但对性能很不利。

这里有一些除了角色模型之外的其他例子。

这些密集的晾衣绳由25000个顶点组成,每条都有几十个独立模型的晾衣夹。甚至还有一个更密集的版本,具有超过3万个顶点。

从技术上讲,这个停车场网格没有在我的示例帧的预通道中使用,但它仍然存在于场景中,后来在阴影映射通道中使用。这个网格由超过四万个顶点组成,没有LOD,并且具有大多数AAA游戏中都没有的奢华细节,例如连接屏幕和键盘的单独建模电缆。它们甚至可以从桌子上的一个相对较圆的洞里穿过去将建筑和家具合并到一个网格中可以节省绘制调用,但这也意味着道具不能单独遮蔽。

这种由一堆原木组成的网格类似地只用于阴影渲染通道,并且具有超过10万个顶点。这是迄今为止我在游戏中遇到的最高的多边形模型,尽管我只玩了几个小时。

现在你可能会说这些只是吹毛求疵例子,而且现代硬件可以很好地处理这些模型。你大致上是正确的,但问题是所有这些相对较小的成本会逐渐积累,特别是在一个城市建造游戏中,一个未优化的模型可能会在一个帧中渲染几百次。无论硬件是否能够处理它,在每帧每实例中对成千上万个多边形进行栅格化并且不影响单个像素都是一种浪费。幸运的是,这些问题很容易解决,既可以通过创建更多的LOD变体,也可以通过改进遮蔽系统来解决。但这需要一些时间,CO和P是否愿意投入时间还有待观察,特别是如果这涉及到检查大部分游戏资产并逐一修复它们的话。

需要明确的是,拥有非常详细的模型本身并不是问题,特别是如果你打算创造一款自称为“次世代城市建造游戏”的话。问题在于,游戏很难处理这种级别的细节,而且多边形的使用效率低下且不一致。每个具有丰富建模的的角色模型,都可以被低多边形的模型给替代。我认为如果游戏运行良好,人们将会大肆宣扬这些非常细致的模型,并社交媒体上发表那些标题党帖子,比如“天哪,开发者想到了一切🤯🤯🤯”和“我不敢相信他们模拟了停车场的电缆😱😱😱”和“城市天线2最精细的游戏?”的标题视频。但如今,我们面临的情况却又如此糟糕

让我们回到正题。

运动矢量

游戏渲染每像素的运动矢量作为一个单独的通道,这可以用于抗混叠和运动模糊。我认为现在的运动矢量有点运作不良,这也是游戏在撰写本文时不支持DLSS或FSR2的原因。在高级设置菜单中隐藏了一个临时抗锯齿选项,它在一定程度上提高了渲染质量,但是使用顶点着色器的动画,比如树,只是被伪影和鬼影覆盖了。

这个过程大约需要0.6毫秒。

道路和贴片

现在我们终于渲染了一些能认出来的东西道路还有草坪,以及其他沿着地形表面延伸的东西。

这个过程大约需要1毫秒。

主要通道

这是延迟渲染过程中的主要过程。这个通道将所有中间渲染目标与虚拟纹理缓存和一些看似硬编码的纹理一起产生,并产生更多的缓冲区,包括反射率,法线,不同的PBR属性和深度。它还生成我之前提到的虚拟纹理可见性信息。它以半水平分辨率呈现,可能是一种优化。地形不使用虚拟纹理,所以它以全分辨率和恒定的颜色渲染,而不考虑实际地形纹理。

虚拟纹理可见性缓冲区

这个过程需要16.7毫秒,如果我们的目标是每秒60帧,那么他花掉了整个帧的预算。这个通道再次栅格化了所有的几何图形,所以使前置通道变慢的原因也适用于这里。额外的成本可能是由于额外输出的数量,加上虚拟纹理缓存查找和纹理映射本身的成本。

环境光遮蔽

接下来,游戏将使用运动向量、法线和深度缓冲以及前一帧的最后两个副本来生成环境光遮蔽缓冲。根据着色器的调试名称判断,算法是GTAO。这大约需要1.6毫秒。

级联阴影映射

城市:天际线2》使用了层叠阴影贴图,在我看来效果不是很好。阴影中充满了伪影,尤其是当太阳或任何树叶移动时它们一直都在移动,阴影会不断闪烁。即使屏幕没有完全被伪影覆盖,阴影的分辨率也相当低,不同阴影级联之间的质量差异也非常明显。

游戏使用四个级联,每个级联的分辨率为2048 × 2048像素。在高级图形设置菜单中有一个方向阴影地图分辨率设置,但在本文撰写时,它没有连接到代码中的任何内容无论是单个设置还是整体阴影质量设置都不会改变阴影贴图的分辨率。这就是为什么中阴影和高阴影设置预设是完全相同的原因。我不知道这是一个疏忽,还是因为它引起了问题而匆忙禁用了设置。低预设不同于中高预设,因为它消除了地形投射的阴影。

尽管质量较低,但它是迄今为止最慢的渲染过程,大约需要40毫秒或几乎占总帧时间的一半。就绘制调用的数量而言,它也使所有其他通道相形见绌:在我的测试帧中,6705个绘制调用中有4828个用于阴影映射,这一比例达到了惊人的72%。这就是为什么当禁用阴影时,性能会有如此巨大的提升。

这个通道之所以如此缓慢,背后的原因与前置通道和主通道是一样的太多不必要的几何渲染和太多的渲染调用。Renderdoc的性能计数器视图表明,许多渲染调用在阴影地图中造成的影响在0到100像素之间,并且牙齿又回来了。这款游戏似乎将每个3D对象视为潜在的阴影对象,无论大小或距离如何。这里有很多优化的空间,理论上对LOD遮挡的一般改进应该对阴影映射性能也有很大的影响。希望在性能得到改善后,CO或民间Mod玩家可以将阴影质量设置恢复,并将阴影分辨率提高到2023年的水准

让我们以积极的一面来结束这部分内容在深入研究阴影处理代码时,我偶然发现游戏会使用当前日期、时间和城市坐标来计算太阳和月亮的位置。这是一个非常有趣的细节

幕空间反射和全局照明

游戏使用Unity HDRP内置的屏幕空间反射SSR和屏幕空间全局照明SSGI)进行实现。我不会详细介绍它们,因为Unity的文档已经相当全面了,而且我也不会假装自己完全理解它们。全局照明使用ray-marching,默认以半分辨率进行评估。采用去噪和时间积累技术提高图像质量。如果这款自诩为次世代城市建造的游戏除了支持这些屏幕空间解决方案外,还支持硬件加速光线追踪,那就再好不过了,但我并不抱太大希望。

延迟照明

这是最终的产物。到目前为止产生的大多数中间缓冲都被组合起来渲染接近最终的图像。关于这个通道没有太多可说的,除了它大约需要2.1毫秒。

奇怪的衣服通道

有一个小的渲染通道只是为渲染Didimo角色的衣服,在这种情况下,有着3件连衣裙,1件连体衣和1套西装裤子。剩下的8个角色要么赤身裸体,要么他们的衣服使用不同的着色器。此通道在此缩放级别下几乎不影响像素。幸运的是,这只需要0.2毫秒。

天空渲染

接下来使用之前生成的天空盒纹理渲染天空,尽管它在我的示例帧中不可见。这个过程大约需要0.3毫秒。

透明对象预通道

传统的延迟渲染不适用于透明对象,因此它们是单独渲染的。透明对象的渲染分两个阶段,从这个预通道开始,它只更新法线和深度缓冲区。这一帧中没有很多独特的透明对象,所以这个过程大约需要0.12毫秒。

水体渲染

游戏在计算着色器中做一些预处理,为水渲染做准备,然后在产生几个降格和模糊的版本,应用到最终的图像中。这些输入被馈送到渲染水面的主水渲染着色器。这大约需要1毫秒。

粒子、雨和透明物体

这个通道处理大多数透明的东西,包括粒子、天气效果和由玻璃和其他透明材料制成的3D物体。画面中没有可见的颗粒,但游戏仍然试图渲染工业区烟囱里的烟雾,以及污水管道产生的泥浆流。接下来渲染雨水,这部分使用20个实例,每个实例有1.2万个顶点。有趣的是,剩下的透明物体是在下雨后渲染的,因此当透明物体如温室和电线和雨重叠时,会产生一些奇怪的现象。所有这些大约需要0.56毫秒。

虚拟纹理反馈处理

我们之前得到的虚拟纹理可见性缓冲是用计算着色器处理的,结果输出纹理是原始分辨率的1/16。为了展示,我将最近邻的输出缩放为8倍,这样更容易读。这是游戏最终从GPU获得的信息,用于决定加载和卸载哪些纹理贴图。Renderdoc报告在这上面花费的时间很少,不到0.1毫秒。

一些后处理

这款游戏使用了许多Unity内置的后期处理效果,包括时间AA就像我之前提到的,非常崩坏),bloom和色调映射,以及DOF和动态模糊如果启用。我懒得总结所有这些效果,但总共花费大约是1到2毫秒。

轮廓,文本和其他UI

最后剩下的渲染调度用于渲染所有不同的UI元素,既包括绘制到世界中的元素,也包括更传统的UI元素,如底部栏和其他控件。许多渲染用于GamefaceUI元素,尽管最终这些调度与渲染过程的其余部分相比非常快。道路名称使用2D符号距离字段渲染到场景中。如果文本位于建筑物或其他物体的后面,游戏会使用深度缓冲将文本与场景混合,这是一个很好的设计。这最后一个通道花费的时间较少

至此就大功告成了!

我试着不把它变成深入的图像研究,但我想我失败了。希望你学到了一些新东西。

总结

那么为什么《城市:天际线2》对GPU的要求如此之高呢?简而言之,游戏在显卡上投放了太多不必要的几何图形,以至于游戏在很大程度上受到可用的栅格化性能的限制。造成不必要几何体的原因是许多游戏网格缺乏简化的LOD变体,以及过于简单和看似未调整的遮蔽执行。游戏之所以使用自己的遮蔽执行而不是使用Unity的内置解决方案理论上应该更先进是因为Colossal Order必须自己执行许多图像方面的内容,因为Unity在DOTS和HDRP之间的整合仍处于开发阶段,并且可能不适合大多数实际游戏。同样地,Unity的虚拟纹理解决方案仍然处于测试阶段,所以Colossal Order也必须执行他们自己的解决方案,这仍然存在一些初期问题。

以下是我认为发生的事情Colossal Order在Unity的新技术上进行了赌博,在某些方面它获得了巨大的回报,但在其他方面却给他们带来了很多麻烦。这在软件开发中并不罕见,我自己作为一名学习网络的开发人员,在日常工作中也经历过这种情况。他们选择DOTS作为架构来修复之前游戏所遭遇的CPU瓶颈,并增加模拟的规模和深度,并且在这方面取得了很大的成功。Colossal Order在DOTS还处于实验阶段时便开始了这款游戏,并且即使在DOTS正式被认为可以投入生产时,他们也不得不自己执行这么多内容。如果他们一开始使用实体图像,但当他们意识到Unity的官方解决方案无法解决问题时,他们不得不转向自定义解决方案,如遮蔽、骨骼动画、纹理流等,我不会对此感到惊讶。最终,由于资金和发行商的压力,游戏不得不在这些系统尚未完善时过早发布。这些技术问题在发布当天对开发者来说都不是什么新闻。他们一开始就宣称游戏的目标是30 FPS,这十分令人难以置信——自21世纪初以来,没有一款纯PC游戏只有30帧的,哪怕图像规格再高也不应如此

虽然我确实发现了很多关于游戏技术的抱怨,也让我在过去的1.5周内耗费了我大量空闲时间进行调查,但这个过程也让我欣赏了这款游戏的崇高目标,并更加同情这款在技术上雄心勃勃但却陷入困境的游戏的开发者。我已经学到了很多关于《城市天际线2》和Unity HDRP的工作原理,我也得到了一些RenderDoc上很好的实践。

如若转载,请注明出处:http://www.gamelook.com.cn/2023/11/531573

关注微信