优化 VR 动作类游戏《Space Pirate Trainer*》以便在英特尔® 集成显卡上实现卓越的表现

Space Pirate Trainer game

作者:Cristiano Ferreira (@cristianohh)、Dirk Van Welden (@quarkcannon) 和 Seth Schneider (@SethPSchneider)

Space Pirate Trainer* 是一款面向 HTC Vive*Oculus Touch*Windows Mixed Reality* 的原创发行游戏。版本 1.0 于 2017 年 10 月发布,并迅速获得成功,在全球 VR 市场中占据一席之地。RoadtoVR.com显示其销售量已超过 150,000 份。它甚至已经成为许多硬件制造商用来演示 VR 奇迹的首选。

“我永远都不会制作 VR 游戏!”这话出自 I-Illusions 首席执行官和 Space Pirate Trainer 创意总监 Dirk Van Welden 之口。他在首次使用原型 Oculus Rift* 后发表了这一评论。作为Kickstarter* 最初的项目赞助商,他收到这款游戏作为回报,但这款游戏并没有给他留下深刻的印象。经历了严重的晕动症后,他基本上准备放弃 VR。

幸运的是,位置跟踪出现了,因此他准备通过 HTC Vive 原型再次尝试 VR。经过一个月的试验,他们完成了首个 Space Pirate Trainer 原型。Van Welden 在 SteamVR* 论坛上发布这一原型以获取反馈。而且他发现,随着新版本的发布,受众不断增多。该游戏引起了 Valve* 的注意,他们邀请 I-Illusions 参加 SteamVR 开发者展会,向媒体介绍 Space Pirate Trainer。Van Welden 知道自己具备这种实力,因此接受了邀请。即使处于预测阶段,游戏也大受欢迎。

什么是主流 VR?

主流 VR 是指降低进入 VR 的门槛,支持用户在不大量投资硬件的情况下玩一些最流行的 VR 游戏。为了获得最高端的 VR 体验,图形处理方面的最低规格要求使用NVIDIA GeForce* GTX 970 或更高版本。除了购买昂贵的独立显卡外,玩家还需支付数百美元 (USD) 购买头显和传感器组合。投资可能瞬间增多。

但如果我们能在带有集成显卡的系统上执行 VR 游戏呢?这将意味着所有拥有顶级 Microsoft Surface* Pro英特尔® NUC超极本™ 设备的移动用户都可以玩顶级 VR 游戏。您可以搭配不需要采用外部跟踪器的 Windows Mixed Reality 头显,随时随地设置 VR。听起来令人难以置信?Van Welden 和我也这么认为,但我们发现,您只需作出极小的权衡,就可获得出色的 VR 体验。

pre-beta and version 1.0

图 1.Space Pirate Trainer* - 预测版(左)和版本 1.0(右)。

在采用集成显卡的 13 瓦 SoC 上以 60 fps 的速度渲染双眼?什么?

那么,您如何让 VR 游戏在集成显卡上运行?在 NVIDIA GeForce GTX 970 目标版本不作出任何更改的情况下,Space Pirate Trainer 的初始端口以 12 fps 的速度运行。主流空间所需的帧速率仅为 60 fps,给我们留出了 48 fps 的空间来通过优化提升性能。非常幸运,我们发现了许多可以轻易实现的目标 — 能极大地提升性能,且几乎不会影响游戏的美学效果。以下是并排比较:

Comparison of Space Pirate Trainer at 12 and 60 f p s

图 2.12 fps(左)和 60 fps(右)的 Space Pirate Trainer*比较。

入门

VR 开发人员几乎没有优化集成显卡的经验,而且有一些重点需要注意。在桌面配置和优化中,一般不需要考虑热量(产生热量)问题。通常可以单独考虑 CPU 和 GPU,并假定它们都将以完整时钟速率运行。遗憾的是,SoC(系统芯片)并非如此。“集成显卡”意味着 GPU 与 CPU 集成在相同的芯片上。每次电流通过电路时,会产生一定的热量并辐射于整个部件。由于这种情况发生在 CPU 和 GPU 端,因此整个封装都会产生大量的热量。为确保芯片不被损坏,CPU 或 GPU 的时钟速率必须可以调节,以支持间歇性散热。

为了保持一致性,最好使用基于可预测散热模式的测试系统作为基准。这样您可以在试验时始终有可靠的参考点,以验证性能提升或降低。为此,我们建议使用 GIGABYTE Ultra-Compact PC GB-BKi5HT2-7200* 作为基准,因为它的热量一致。一旦游戏在机器上运行的速度始终保持 60 fps,就可以针对各个原始设备制造商 (OEM) 的机器了解它们的工作原理。每台笔记本电脑都有自己的散热解决方案,因此有助于在常见的机器上运行游戏,以确保其冷却方案能够跟上运行速度。

System specs for G B - B K i 5 H T 2 - 7 2 0 0
图 3.GIGABYTE 超紧凑型 PC GB-BKi5HT2-7200* 的系统规格。

* 产品可能因当地的分销而有所不同。

  • 采用最新第七代智能英特尔® 酷睿™ 处理器
  • 仅 0.6L(46.8 x 112.6 x 119.4 毫米)的超紧凑型 PC 设计
  • 支持 2.5 英寸 HDD/SSD,厚度为 7.0/9.5 毫米 (1 x 6 Gbps SATA 3)
  • 1 个 M.2 SSD (2280) 插槽
  • 2 个 SO-DIMM DDR4 插槽 (2133 MHz)
  • 英特尔® IEEE 802.11ac,双频 Wi-Fi 和蓝牙 4.2 NGFF M.2 卡
  • 英特尔® 核芯显卡 620
  • 1 个 Thunderbolt™ 3 端口 (USB 3.1 Type-C™)
  • 4 个 USB 3.0 (2 x USB Type-C™ )
  • 1 个 USB 2.0
  • HDMI 2.0
  • HDMI 加 Mini DisplayPort 输出(支持双显示屏)
  • 英特尔千兆位局域网
  • 双阵列麦克风(支持语音唤醒和 Cortana)
  • 耳机/麦克风插孔
  • VESA 安装支架(75 x 75 毫米 + 100 x 100 毫米)
  • * 所包含的无线模块可能因当地的分销而有所不同。

目前英特尔的所有优化均使用上述系统,以取得一致的结果。出于本文之目的和我们提供的数据,我们来看 Microsoft Surface Pro:


图 4.用于测试的 Microsoft Surface * Pro 的系统规格。

支持 10 个触摸点的手写笔和触摸支持

面向...优化 
设备名称GPA-MSP
处理器英特尔® 酷睿™ i7-7660U CPU @ 2.50GHz 2.50 GHz
安装的 RAM16.0 GB
设备 IDF8BBBB15-B0B6-4B67-BA8D-58D5218516E2
产品 ID00330-62944-41755-AAOEM
系统类型64 位操作系统,基于 x64 的处理器
手写笔和触摸

对于此次密集优化,我们使用了英特尔® 图形性能分析器(英特尔® GPA) — 一套图形分析工具。我不逐一介绍各个细节,但大多数情况下我会使用图形帧分析器。不管怎样,下面我们进入优化阶段!

优化

为了达到 60 fps 的速度且不影响美学效果,我们尝试了许多试验。下表列出了优化在提升性能和最大限度地减少艺术影响方面所带来的最大优势。当然,每款游戏都不相同,但试验时可以首先执行以下步骤。

着色器 — 地板

第一个优化可能是最简单、最有效的改变。场景中的地板占据较大的像素范围。

Floor scene with the floor highlighted

图 5.地板场景,其中高亮显示地板。

上图显示了帧缓冲器中用洋红色高亮显示的地板。图中,场景中的地板占据了 60% 的像素覆盖范围。这意味着影响地板的材质优化将对保持较低的帧预算产生巨大影响。Space Pirate Trainer 使用带有反射探头的标准 Unity* 着色器获取表面的实时反射。反射是一项很好的特性,能够在我们的目标系统上计算和采样每一帧,只是有一点昂贵。我们用简单的 Lambert* 着色器替换标准着色器。不仅保存了反射采样,还避免了使用 Windows 混合现实游戏所用的正向渲染系统时标记为“重要”的动态灯所需的额外通道。

Measurements for rendering the floor before optimizations

图 6.优化前渲染地板的原始测量值。

Measurements for rendering the floor after optimizations

图 7.优化后渲染地板的测量值。

通过上述性能比较,我们可以发现,渲染地板的原始成本大约是每帧 1.5 毫秒,替换着色器后,成本仅为每帧 0.3 毫秒。性能提升了 5 倍。

The assembly for shader reduced to only 47

图 8.着色器的汇编由 267 条指令(左)减少至 47 条(右),且每次取样的像素着色器调用次数明显减少。

如上图所示,我们着色器的汇编从 267 条指令减少至 47 条,且每次取样的像素着色器调用次数明显减少。

Standard Shader and Lambert Shader

图 9.同一场景的并排比较,左侧是标准着色器,右侧是优化的 Lambert* 着色器。

上图显示了除使用 Lambert 着色器替换标准着色器之外没有任何更改的高端构建。请注意,完成所有这些删减和剪切后,留下的仍然是漂亮的地板。Microsoft 还创建了 Unity 内置着色器的优化版,并将它们作为混合现实工具套件的一部分添加。试试工具套件中的材质,看看它们如何影响游戏的外观和性能。

着色器 — 使用未点亮的着色器进行材质批处理

绘制调用批处理是将共享通用状态属性的独立绘制调用绑定成批处理。渲染线程通常是瓶颈争用的焦点,尤其是在移动设备和 VR 上,而且批处理只是实用程序带中用来消除驱动程序瓶颈的主要工具之一。就 Unity 引擎而言,批量绘制调用的通用属性是材质以及材质所使用的纹理。Unity 引擎支持两种批处理:静态批处理和动态批处理。

静态批处理非常简单,而且非常实用。只要场景中的所有对象在检查器中都标记为静态,与这些对象的网格渲染器组件相关的所有绘制调用都将进行批处理(假设它们共享相同的材质和纹理)。最好的做法是在引擎检查器中标记所有将保持静态的对象,以便巧妙地优化不必要的工作,并使 Unity 引擎中的各个内部系统不考虑这些,对于批处理尤其如此。请记住,对于 Windows 混合现实主流,实例化立体渲染尚未实施,因此所有已保存的绘制调用都将计为两倍。

动态批处理有一点点细微差别。静态批处理和动态批处理在要求方面的唯一不同是必须考虑动态对象的顶点属性数量,并使其低于某一阈值。请务必检查 Unity 文档,了解您所使用的 Unity 版本的阈值是多少。通过英特尔 GPA 图形帧分析器捕捉一帧,验证后台的实际运行情况。见下图 10 和图 11,了解禁用和启用批处理时 Space Pirate Trainer 在帧可视化方面的差异。

Batching and instancing disabled

图 10.批处理和实例化禁用;1,300 次绘制调用;共 150 万个顶点;GPU 持续时间为 3.5 毫秒/帧。

Batching and instancing enabled

图 11.批处理和实例化启用;8 次绘制调用;共 150 万个顶点;GPU 持续时间为 1.7 毫秒/帧(性能提升 2 倍)。

如上图所示,渲染 1,300 艘船(共 150 万个顶点)所需的绘制调用数量从 1,300 下降至 8。在批处理示例中,我们实际上渲染了更多的船(总共 200 万个顶点)来验证这一结论。这样不仅大量节省了渲染线程的时间,还通过更高效地运行图形管道,节省了大量 CPU 时间。实际上我们获得了 2 倍的性能提升。为了最大限度地增加批处理调用的数量,我们还使用了名为纹理图集化 (Texture Atlasing) 的技术。

基本来说,纹理图集是填充到单个大纹理中的不同对象所使用的纹理和 sprite 的集合。为了充分发挥这项技术的作用,需要更新纹理坐标,以与更改保持一致。听起来可能比较复杂,但 Unity 提供实用程序支持轻松自动化完成这一操作。美术师还可以使用所选的建模工具,以熟悉的方式构建图集。回顾不同模式间共享纹理的批处理要求,纹理图集是一种非常强大的工具,可以帮助您在运行时省去大量不必要的工作,从而在不到 16.6 毫秒/帧的时间内完成渲染。

关键要点:

  • 务必将生命周期内永远不会移动的所有对象都标记为静态。
  • 确保待批处理的动态对象的顶点属性少于 Unity 文档中指定的阈值。
  • 确保创建的纹理图集包含尽可能多的可批处理对象。
  • 使用英特尔 GPA 图形帧分析器验证实际行为。

着色器 — 面向机器人激光的 LOD 系统

对于不熟悉该术语的人来说,LOD(细节级别)系统指基于某些参数动态交换各种类型的素材。本节我们将介绍根据摄像头距离交换各种材质的过程。这种想法更进一步,就是应使用更少的资源,在较低的像素覆盖范围内实现最佳的美学效果。对玩家来说,素材的交换不应该太明显。在 Space Pirate Trainer 中,Van Welden 创建了一个系统,将用于机器人激光的 Unity 标准着色器换成更简单的着色器,以便当激光与摄像头达到一定的距离时,与所需的外观相似。请参阅以下示例代码:

using System.Collections;
using UnityEngine;
public class MaterialLOD :MonoBehaviour {

public Transform cameraTransform = null;    // camera transform
public Material highLODMaterial = null;    // complex material
public Material lowLODMaterial = null;     // simple material


public float materialSwapDistanceThreshold = 30.0f;   // swap to low LOD when 30 units away
public float materialLODCheckFrequencySeconds = 0.1f; // check every 100 milliseconds


private WaitForSeconds lodCheckTime;
private MeshRenderer objMeshRenderer = null;
private Transform objTransform = null;
 // « Imaaaagination » - Imagine coroutine is kicked off in Start().Go green and conserve slide space.
 IEnumerator Co_Update () {
objMeshRenderer = GetComponent<MeshRenderer>();
 objTransform = GetComponent<Transform>();
lodCheckTime = new WaitForSeconds(materialLODCheckFrequencySeconds);
    while (true) {
		 if (Vector3.Distance(cameraTransform.position, objTransform.position) > materialSwapDistanceThreshold) {
		     objMeshRenderer.material = lowLODMaterial; // swap material to simple
		}
		else { objMeshRenderer.material = highLODMaterial;   // swap material to complex
		}
		 yield return lodCheckTime;
		}
	}
}

简单着色器的示例代码

这是一个非常简单的更新循环,每隔 100 毫秒检查进行材质交换所要考虑的对象的距离。如果距离超过 30 个单位,材质将被交换出来。请记住,交换材质可能会破坏批处理,因此可以通过试验看看优化如何影响各硬件层的帧时间。

在手动材质 LOD 系统的顶部,Unity 引擎还有一个内置于编辑器的 LOD 系统(访问此处的文档)。我们通常建议迫使低功耗部件上尽可能多的对象达到最低 LOD。对于高保真度可产生重大影响的场景中的关键部分,可以对计算成本更高昂的材质和几何体进行权衡。例如,在 Space Pirate Trainer 中,Van Welden 决定不遗余力地渲染爆破器,因为它们是场景中的关键点。这些权衡有助于游戏保持所需的外观,同时最大化目标硬件并吸引潜在 VR 玩家。

照明和后期效果 — 移除动态灯光

如前所述,当引擎使用正向渲染路径,实时灯光会严重影响 GPU 的性能。这种性能影响主要通过主定向灯影响的模型的其他通道以及检查器中所有标记为重要的灯(质量设置中的像素灯数量设置)显示出来。如果您的模型位于两个重要动态灯和主定向灯的中间,那么至少会看到三个面向该对象的通道。

Contributing 5 ms of frame time for the floor

图 12.Space Pirate Trainer* 中的武器开火时,武器底部点亮的动态灯数量加倍,为地板(高亮显示)提供了 5 毫秒的帧时间。

Space Pirate Trainer 中,低设置下禁用枪筒的点光,以避免这些额外通道,进而节省大量帧时间。回顾地板渲染一节中的内容,想象整个地板被渲染三次。现在考虑必须为双眼进行渲染;您将总共六次绘制覆盖屏幕 60% 像素的几何体。

关键要点:

  • 确保所有动态灯都被移除/标记为不重要。
  • 烘烤尽可能多的灯光。
  • 使用光探头进行动态照明。

后期处理效果

如果不小心,后期处理效果可能会占用大量帧预算。Space Pirate Trainer 的优化的“高”设置使用 Unity 的后期处理堆栈,但表面目标仅耗费约 2.6 毫秒/帧。见下图:

High settings showing 14 passes
图 13.“高”设置显示 14 个通道(大幅减少);GPU 持续时间为 2.6 毫秒/帧。

高亮部分显示 Space Pirate Trainer 后期处理效果涉及的所有绘制调用,显示的弹出窗口为所选调用的总 GPU 持续时间 — 大约 2.6 毫秒/帧。Van Welden 和团队最初测试用移动绽放替代常用的效果,但发现会导致闪烁分散。最终他们决定放弃绽放,并使用颜色查找表将剩余的设计效果整合至一个自定义通道中,以呈现近似高端版本的外观。

合并通道可将帧时间从之前的 2.6 毫秒/帧缩短至 0.6 毫秒/帧(性能提升 4 倍)。这种优化涉及更多,可能需要优秀的技术美术师运用专业知识打造更具风格的游戏,但您完全可以收藏这一实用的技巧以供将来使用。此外,即使移动版 Bloom* 不适用于 Space Pirate Trainer,但测试移动 VFX 解决方案也是一种出色、快速、简单的试验。在某些场景设置下,它们可能只是运行,而且性能更高。通过实施的新后期处理效果通道,检查代表“低”设置场景的帧捕获:

Low settings consolidating all post-processing effects
图 14.“低”设置,将所有后期处理效果整合成一个通道;GPU 持续时间为 0.6 毫秒/帧。

HDR 用法与垂直翻转

“低”层级上避免使用高动态范围 (HDR) 纹理能够以多种方式实现性能提升 — 主要是要求它们的 HDR 纹理和技术(比如色调映射和绽放)非常昂贵。另外还可计算颜色定稿和每像素所需的较多内存来呈现全色范围。最重要的是,在 Unity 中使用 HDR 纹理会使渲染的场景倒置。这一般不成问题,因为最终渲染目标翻转只需 0.3 毫秒/帧,但当以 60 fps 渲染的预算低于 16.6 毫秒/帧,而且需要每只眼睛完成一次翻转(总共约 0.6 毫秒/帧),这将占用帧相当大的一部分。

Single-eye vertical flip
图 15.单眼垂直翻转,291 毫秒。

关键要点:

  • 取消选中场景摄像头上的 HDR 框。
  • 如果必须使用后期制作效果,请使用 Unity 引擎的 后期处理堆栈,而非完全不相干并会执行冗余工作的图像效果。
  • 删除任何需要深度通道的效果(雾等)。

后期处理 — 抗锯齿

多重采样抗锯齿 (MSAA) 非常昂贵。对于低设置,最好切换到时间稳定的后期制作效果抗锯齿解决方案。为了了解 MSAA 在我们的低端目标上有多昂贵,我们来看看在高设置下捕获的 Space Pirate Trainer

ResolveSubresource cost while using Multisample Anti-Aliasing
图 16.使用多重采样抗锯齿 (MSAA) 时的 ResolveSubresource 成本。

ResolveSubresource API 调用是 MSAA 的固定功能,确定启用 MSAA 时渲染目标的最终像素。从上我们可以看出,这一步骤仅耗费 1 毫秒/帧。每次绘制都要进行此操作,而且这些绘制是难以量化的。

或者,还可以采用较便宜的后期制作效果抗锯齿解决方案,包括英特尔开发的时间稳定形态保真抗锯齿 (TSCMAA)。TSCMAA 是可在英特尔® 集成显卡上运行的最快的抗锯齿解决方案之一。如果在升级至本机头盔显示器 (HMD) 分辨率之前,以低于 1280x1280 的分辨率渲染,则后期制作效果抗锯齿解决方案必须避免锯齿并保持良好的体验。

Up to 1.5x with T S C M A A
图 17.相比 4x 多重采样抗锯齿 (MSAA),时间稳定形态保真抗锯齿 (TSCMAA) 可将性能提升 1.5 倍,且输出质量更高。请注意模型边缘的锯齿(台阶)差异。

面向激光的光线投射 CPU 端改进

一般来说,光线投射操作并不十分昂贵,但是当你在 Space Pirate Trainer 中获得尽可能多的动作时,它们很快就会变成一种资源浪费。之所以当大多数 VR 游戏遭遇 GPU 瓶颈时我们担心 CPU 性能,是因为存在热量限制。这意味着系统芯片 (SoC) 的任何工作都会在整个系统封装中产生热量。因此,即使 CPU 不存在技术瓶颈,CPU 工作产生的热量也会为封装提供足够的热量,从而限制 GPU 频率,甚至是自己的 CPU 频率,并导致瓶颈会根据限制的对象和时间而发生变化。

热量的产生使优化过程更加复杂;移动开发人员对此非常清楚。掉进通过集成 GPU 寻找完美标准化 CPU 优化方法的“兔子洞”,只会让人心烦意乱,但完全没有必要。只需将整体优化视作主要目标。使用针对 CPU 和 GPU 的一般最佳实践会取得重大进展。我们不要离题太远,现在回到光线投射优化上来。

这种优化的概念是光线投射检查频率可根据距离而波动。光线投射越远,两次检查之间可以跳过的帧越多。在测试中,Van Welden发现在最坏的情况下,实际的光线投射检查和远处物体的响应仅变化几帧,这在 VR 渲染所需的帧速率下几乎检测不到。

private int raycastSkipCounter = 0;
private int raycastDynamicSkipAmount;
private int distanceSkipUnit = 5;
public bool CheckRaycast()
    {
       checkRaycastHit = false;

       raycastSkipCounter++;
       raycastDynamicSkipAmount = (int)(Vector3.Distance(playerOriginPos, transform.position) / distanceSkipUnit);
       if (raycastskipCounter >= raycastDynamicSkipAmount)
       {
           if (Physics.Raycast(transform.position, moveVector.normalized, out rh,
           transform.localScale.y + moveVector.magnitude • bulletSpeed * Time.deltaTime * mathf.Clamp(raycastDynamicSkipAmount,1,10),
           laserBulletLayerMask)) //---never skip more than 10 frames
           {
               checkRaycastHit = true;
               Collision(rh.collider, rh.point, rh.normal, true);
            }
            raycastSkipCounter = 0;
        }

        return checkRaycastHit;
    }
}

示例代码显示如何进行光线投射优化

以低分辨率渲染和升级

大多数 Windows 混合现实头显每只眼睛的原始分辨率为 1.4k 或更高。由于多个因素,以这种分辨率渲染到目标分辨率可能非常昂贵。要定位低功耗集成显卡组件,将渲染目标设置为较低的分辨率非常有用,然后让全息 API 自动升级分辨率,以适应最终的原始分辨率。这会大大缩短您的帧时间,同时外观仍然看起来不错。例如,Space Pirate Trainer 将双眼渲染成分辨率为 1024x1024 的目标,然后逐步升级。

Upscaled target resolution to 1280x1280
图 18.渲染目标分辨率指定为 1024x1024,而最高目标为 1280x1280。

降低分辨率时需考虑几个因素。当然,所有游戏都不同,降低分辨率会以不同的方式影响不同的场景。例如,包含大量精细文本的游戏可能无法达到如此低的分辨率,或者必须使用不同的技巧来维持文本保真度。有时可以通过将 UI 文本渲染为全尺寸渲染目标,然后将其传送至低分辨率渲染目标的顶部,实现这一目标。渲染场景几何体时,这种技巧可以节省大量计算时间,但不会影响整体体验质量。

另外需要考虑的一个因素是抗锯齿。渲染目标的分辨率越低,抗锯齿的可能性越大。如前所述,我们可以使用后期制作效果抗锯齿技术挽回部分质量损失。考虑抗锯齿成本之后,以低分辨率渲染场景的像素调用节省通常为净正值。

#define MAINSTREAM_VIEWPORT_HEIGHTMAX 1400
void App::TryAdjustRenderTargetScaling()
 {
      HolographicDisplayA defaultHolographicDisplay = HolographicDisplay::GetDefault();
      if (defaultHolographicDisplay == nullptr)
      {
          return;
      }
Windows::Foundation::Size originalDisplayViewportSize = defaultHolographicDisplay-MaxViewportSize;
 if (originalDisplayViewportSize.Height < MAINSTREAM_VIEWPORT_HEIGHT_MAX)
 {
     // we are on a 'mainstream' (low end) device.
     // set the target a little lower.
     float target = 1024.0f / originalDisplayViewportSize.Height;
     Windows::ApplicationModel::Core::CoreApplication::Properties->Insert("Windows.Graphics.Holographic.RenderTargetSizeScaleFactorRequest”, target);
}

用于调整渲染目标缩放的示例代码

首先渲染 VR 手部以及其他排序注意事项

在大多数 VR 体验中,某种形式的手部替换经过渲染,可以呈现玩家实际手部的位置。在 Space Pirate Trainer 中,不仅渲染手部替换,还渲染玩家的爆破器。不难想象,这些东西会覆盖双眼渲染目标的大量像素。显卡硬件有一项称为早期 z 拒绝的优化,允许硬件对比正在渲染的像素的深度和上一个渲染的像素的现有深度值。如果当前像素距离上一像素较远,则不需要写入像素,并且可节省该像素着色器和图形管道的所有后续阶段的调用成本。图形渲染的工作方式类似颠倒的绘图工具算法。绘图工具通常从后往前绘制,同时由于这种优化,您也可以从前往后渲染游戏场景,进而获得巨大的性能优势。

Drawing the blasters in Space Pirate Trainer
图 19.在帧的开头绘制 Space Pirate Trainer* 中的爆破器,可以保存所有被覆盖的像素的像素调用。

很难想象,VR 双手和手握的道具不是最接近摄像头的网格。因此,我们可以做出明智的决定,迫使首先绘制手部。在 Unity 中很容易做到这点;您只需找到与手部网格相关的材质,以及可以捡拾的道具,并覆盖它们的 RenderQueue 属性。我们可以确保,通过使用 UnityEngine.Rendering 命名空间中提供的 RenderQueue 枚举,在所有不透明对象之前进行渲染。有关示例,请参见下图。

namespace UnityEngine.Rendering
{
           ...public enum RenderQueue
           {
                ...Background = 1000,
                ...Geometry = 2000,
                ...AlphaTest = 2450,
                ...Geometrylast = 2500,
                ...Transparent = 3000,
                ...Overlay = 4000
           }
} 

UnityEngine.Rendering 命名空间中的 RenderQueue 枚举

using UnityEngine;
using UnityEngine.Rendering;
0 references
 public class RenderQueueUpdate :MonoBehaviour {
        public Material myVRHandsMaterial;

        // Use this for initialization
       0 references
       void Start () {
               // Guarantee that VR hands using this material will be rendered before all other opaque geometry.
               myVRHandsMaterial.renderQueue = (int)RenderQueue.Geometry - 1;
       }
}

覆盖材质的 RenderQueue 参数的示例代码

如果需要,可以进一步覆盖材料的 RenderQueue 顺序,因为任何给定时刻,场景装饰存在逻辑分组。场景可以按下列顺序分类(见下图)和排序:

  1. 绘制 VR 手和任何可互动的部件(武器等)。
  2. 绘制场景装饰。
  3. 绘制大件(建筑物等)。
  4. 绘制地板。
  5. 绘制天空盒(如果使用内置 Unity 天空盒,那么这一步骤通常已经完成)。

Categorizing the scene helps the RenderQueue order
图 20.覆盖 RenderQueue 顺序时,对场景进行分类可能会有所帮助。

Unity 引擎的排序系统通常会很好地处理这个问题,但有时也会发现不遵守规则的对象。与往常一样,首先在 GPA 中检查场景的帧,确保这些方法在应用之前已准确排序。

天空盒压缩

最后是简单的修复,具有一些潜在的优势。如果场景中使用的天空盒纹理不进行压缩,则可以获得巨大提升。根据游戏的类型,天空可以覆盖每一帧的大量像素;让采样尽可能的轻,因为像素着色器可以对帧速率产生积极影响。此外,当游戏检测到它在主流系统上运行时,它还可帮助降低天空盒纹理的分辨率。请参阅 Space Pirate Trainer 中显示的性能比较:

Lowered skybox resolution from 4k to 2k
图 21.简单地将天空盒分辨率从 4k 降到 2k,可以实现 5 倍的性能提升。通过压缩纹理可以进行其他改进。

结论

最后,我们在 13 瓦集成显卡部件的“低”设置上以 60 fps 运行 Space Pirate Trainer。随后,Van Welden 将许多优化反过来应用到高端平台的原始版本中,这样所有人都可以受益,即使是在高端版本中也可受益。

Final result - 4 ways faster
图 22.最终结果:从 12 fps 升至 60 fps。

之前运行速度为 12 fps 的“高”设置,现在在集成显卡系统上的运行速度为 35 fps。将进入 VR 的门槛降低至 13 瓦笔记本电脑可以让更多玩家畅玩您的游戏,帮助您提高销量。立即下载英特尔 GPA 并开始在您的游戏中应用这些优化。

资料来源

Space Pirate Trainer

英特尔图形性能分析器工具套件

TSCMAA

Unity Optimization Article

有关编译器优化的更完整信息,请参阅优化通知