大家好!我是来自 High Horse Entertainment 的 Jay,我们是洛杉矶的一个两人团队。High Horse 的创立宗旨时开发拥有当代主流画面和控制模式,以及激烈在线竞争性的街机游戏。我们的首个项目 Disc Jam 是一款街机运动类游戏,强调时机和反应。如您有兴趣一试身手,可以在 www.discjamgame.com 免费获取 pre-alpha 版本的 Steam 码!
性能是这个项目的重中之重,因为达到每秒 60 帧才能保证 Disc Jam 快速而流畅的游戏特点。因此,我们为使用虚幻引擎 4 达到该帧率而学习了大量教程。以下我将分享针对 Intel 集成 GPU 进行开发的经验,说明如何在不提高最低系统要求的前提下最终达到性能目标。
为什么要以集成 GPU 为目标进行开发呢?
因为缺乏硬件标准化,PC 开发较之于主机开发更具有技巧性。在大量的 PC 游戏玩家中,一部分拥有独立 GPU,而相当大的一部分仍在使用集成 GPU。这个市场的具体规模难以得知,但 Unity Technologies 收集的现今硬件数据显示,将近 40% 的游戏电脑使用 Intel 的 GPU,高于其他硬件供应商。许多 PC 游戏可通过提高最低系统要求来解决这个问题,但 Disc Jam 却必须尽量降低系统要求,原因有二:
并发性
Disc Jam 这类多人游戏的兴起和衰落皆由并发性所决定。如果没有玩家进行游戏,玩家则无法找到比赛,玩家基础将缩小,直至完全消失。因此,支持尽量多的硬件配置对我们来说十分重要。
性能
Disc Jam 的目标游戏帧率为 60 帧每秒(fps)。如果玩家的系统无法维持该帧率,则无法获得预期的游戏体验。这还可能影响队友和对手的游戏体验,因为 Disc Jam 实际上是一款网游。
虚幻引擎 4 可延展性和性能
决定一种方法时,我们首先在目标硬件上“创造性地”审视虚幻引擎 4 的性能。在这个测试中,我们使用虚幻引擎 4.12.5 的二进制版本和 Shooter Game 范例。所有测试均在一台拥有 Intel® Core™ i7-4720 HQ 处理器和 Intel® HD Graphics 4600 GPU 的笔记本电脑上进行。Runn
Figure 1. Epic 精度设置 - ~20fps
Figure 2. 低精度设置:~40fps
如果我们游戏的目标帧率为 30 fps,这将是个好消息。但我们真心需要达到 60 fps(甚至在最低配置上也必须如此)。制作出比 Shooter Game 范例更为精简的场景已非易事,我们发现虚幻引擎 4(UE4)桌面渲染器针对硬件目标的基础性能开销过高。幸运的是,加上一点创意和技巧,UE4 就能提供一个替代方案。
虚幻引擎 4 的 Mobile Preview 渲染器
虚幻引擎不但能开发高端电脑和主机游戏。也能开发高端移动游戏!因此它提供了许多不同的渲染路径,以支持市场上琳琅满目的移动设备。我们最感兴趣的是最高端的路径,针对 OpenGL 设计的嵌入式系统(ES)3.1 + Android 延展包(AEP)的路径。我们的测试结果表明该路径在 Intel 的集成 GPU 上能达到性能和精度的最佳平衡。
关键在于 UE4 拥有一个名为 Mobile Preview 的功能。此功能的设计理念是无需部署即可在移动设备上预览游戏内容,从而减少迭代时间。它允许用户有效地使用移动渲染路径渲染桌面上的游戏,而不使用 Unreal 通常采用的完整延迟渲染器。使用此功能我们将看到以下结果:
Figure 3. OpenGL ES 3.1 + AEP Mobile Preview:~100fps
在 Mobile Preview 中运行可得到桌面渲染器最低设置的 2.5 倍速度。这样我们就能在集成 GPU 上达到 720p @ 60 fps 的目标啦!您会发现桌面渲染器的截图和移动渲染器的截图之间存在一些视觉差异。这是因为移动渲染器存在一些限制,尤其是在灯光和阴影方面。在 Epic 移动平台的光照和移动设备性能指南 文档中可查阅到详细内容。
多个光照设备
为解决上述问题,使 Disc Jam 中的球场光照始终如一,我们选择使用多个光照设备。使用传统渲染器渲染时使用一个光照设备,在 Preview 中进行渲染时使用另外一个。每款游戏的光照需求都不尽相同,而 Disc Jam 实际使用的是两套相同的光照,唯一的区别是主要投射阴影的光源的移动性。在高端版本中,主光源为一个静止的聚光源。在 Mobile Preview 中我们使用一个静止聚光源,因此所有光照均为预烘焙,有助于榨取更多性能。
Figure 4. Disc Jam* 高端渲染器和光照
Figure 5. Disc Jam* 低端渲染器和光照
在 UE4 中尝试使用多个光照设备时会遇到的首个问题是烘焙光照将和地图中的几何体一同保存,而并非和光照一同保存。不幸的是,这意味着需要将所有几何体复制到另一个地图中,以便烘焙另一套光照。
我们针对 Disc Jam 设置了一个不变关卡,其中放置的所有 actor 均不受光照影响。这些 actor 在地图的高端和低端版本之间共享,并包含生成点和碰撞体积域之类的内容。之后我们便得到包含相同几何体的一个高端地图和一个低端地图,二者只存在光照的区别。关卡加载时,将流入正确的版本:
Figure 6. Disc Jam 的不变关卡蓝图
以上使用的“Is in Mobile Preview”节点为一个自定义 C++ 函数,定义如下:
bool UDiscJamBlueprintFunctionLibrary::IsInMobilePreview() { return GMaxRHIFeatureLevel <= ERHIFeatureLevel::ES3_1; }
打包和部署
请注意:以下部分讨论 Windows 上的打包和部署。其他操作系统上的步骤应和显示的步骤较为相似。
打包游戏并尝试通过命令行参数“-FeatureLevelES31”运行后,便会立即明确必要的着色器未包含在包中。在 Project Settings → Platforms → Windows → Targeted RHIs 下可找到选择不同着色器变体进行打包的复选框,但不巧的是 OpenGL ES 3.1 并未包含在内。添加此着色器需要进行两段简单的代码修改。
在 GenericWindowsTargetPlatform.h 中,必须对 GetAllPossibleShaderFormats 函数进行修改,将 OpenGL ES 3.1 着色器包含在内:
virtual void GetAllPossibleShaderFormats( TArray<FName>& OutFormats ) const override { // no shaders needed for dedicated server target if (!IS_DEDICATED_SERVER) { static FName NAME_PCD3D_SM5(TEXT("PCD3D_SM5")); static FName NAME_PCD3D_SM4( TEXT( "PCD3D_SM4" ) ); static FName NAME_PCD3D_ES3_1( TEXT( "PCD3D_ES31" ) ); static FName NAME_GLSL_150(TEXT("GLSL_150")); static FName NAME_GLSL_430(TEXT("GLSL_430")); OutFormats.AddUnique(NAME_PCD3D_SM5); OutFormats.AddUnique(NAME_PCD3D_SM4); OutFormats.AddUnique(NAME_PCD3D_ES3_1); OutFormats.AddUnique(NAME_GLSL_150); OutFormats.AddUnique(NAME_GLSL_430); } }
然后在 WindowsTargetSettingsDetails.cpp 中修改 GetFriendlyNameFromRHIName 函数,添加友好名称显示 UI:
FText GetFriendlyNameFromRHIName(const FString& InRHIName) { FText FriendlyRHIName = LOCTEXT("UnknownRHI", "UnknownRHI"); if (InRHIName == TEXT("PCD3D_SM5")) { FriendlyRHIName = LOCTEXT("DirectX11", "DirectX 11 (SM5)"); } else if (InRHIName == TEXT("PCD3D_SM4")) { FriendlyRHIName = LOCTEXT("DirectX10", "DirectX 10 (SM4)"); } else if (InRHIName == TEXT("PCD3D_ES31")) { FriendlyRHIName = LOCTEXT("DirectXES31", "DirectX Mobile Emulation (ES3.1)"); } else if (InRHIName == TEXT("GLSL_150")) { FriendlyRHIName = LOCTEXT("OpenGL3", "OpenGL 3 (SM4)"); } else if (InRHIName == TEXT("GLSL_430")) { FriendlyRHIName = LOCTEXT("OpenGL4", "OpenGL 4 (SM5, Experimental)"); } else if (InRHIName == TEXT("SF_VKES31")) { FriendlyRHIName = LOCTEXT("Vulkan ES31", "Vulkan Mobile (ES3.1, Experimental)"); } else if (InRHIName == TEXT("SF_VULKAN_SM4")) { FriendlyRHIName = LOCTEXT("VulkanSM4", "Vulkan (SM4)"); } else if (InRHIName == TEXT("SF_VULKAN_SM5")) { FriendlyRHIName = LOCTEXT("VulkanSM5", "Vulkan (SM5)"); } return FriendlyRHIName; }
完成修改并重新编译引擎后,只需勾选 Windows 平台设置下的框即可:
Figure 7. 新建的“DirectX Mobile Emulation (ES3.1)”将出现
额外说明:在 Intel GPU 上自动启用 Mobile Preview
通过 Steam 运行选项运行后,Disc Jam 允许玩家选择所使用的渲染器。选择低端渲染器将以“-FeatureLevelES31”命令行选项运行游戏。
Figure 8. Disc Jam Steam 运行选项
然而,Intel 的 GPU 将使游戏默认选择 Mobile Preview 渲染器。需要进行简单的代码修改。在 WindowsD3D11Device.cpp 中,函数 FD3D11DynamicRHI::InitD3DDevice() 将初始化显示适配器。在函数下方约 100 行的位置,代码将检查是否使用的是 Intel GPU,以便对显存进行正确配置。在该代码段中,可对渲染器进行如下设置:
if ( IsRHIDeviceIntel() ) { // It's all system memory.FD3D11GlobalStats::GTotalGraphicsMemory = FD3D11GlobalStats::GDedicatedVideoMemory; FD3D11GlobalStats::GTotalGraphicsMemory += FD3D11GlobalStats::GDedicatedSystemMemory; FD3D11GlobalStats::GTotalGraphicsMemory += ConsideredSharedSystemMemory; GMaxRHIFeatureLevel = ERHIFeatureLevel::ES3_1; GMaxRHIShaderPlatform = SP_PCD3D_ES3_1; }
然后就大功告成啦!
如本文对您有所帮助,请在 Twitter 上给我们留言 @HighHorseGames。如要关注 Disc Jam 的开发过程,可在 http://www.discjamgame.com 查看我们的博客。
在此处可阅读 Intel 开发者专区博客中的原文。