〔Part 3〕Oculus Medium移动工具的开发日记
延伸阅读:
〔Part 2〕Oculus Medium移动工具的开发日记
延伸阅读:
〔Part 1〕Oculus Medium移动工具的开发日记
在本文中,我们将会讨论如何异步安排对性能要求巨大的操作。从创意应用到游戏,这对所有需要同时维持VR帧率和运行计算量巨大的任务的软件而言都十分有用。
1. 实时预览
我们将Move Tool操作分为两个阶段:第一个是实时预览;第二个是所需时间更长的移动操作处理。
在第一阶段中,响应时间是关键。你需要能够通过细微的手部运动来操作雕刻。在雕刻时,“看起来逼真”与“看起来不对劲”之间只是一线之差,所以Medium必须允许你移动双手并实时判断结果。
为了实现这一点,第一个阶段要通过Move Tool的位移字段来抵消顶点着色器中的顶点位置。这对性能几乎没有影响,因为它只是位移矢量的简单计算,以及添加到每个顶点位置的偏移量。然而,这个阶段确实需要一些可以影响渲染质量(但不是性能)的捷径。例如,这个阶段不会重新计算网格的顶点平均量,因为它正在变形,而且我们不重新计算环境遮挡。
在第二阶段中,我们将处理对性能要求更高的任务:我们变形三角网格,将变形网格转换回一个指向距离场,并从SDF重新生成三角网格。这能有效重新拓扑化曲面,从而允许操作均匀镶嵌网格的后续移动操作。作为从SDF重新生成网格的一部分,我们重新计算顶点平均量和环境遮挡。在这个阶段之后,雕刻将再次正确地呈现。
尽管我们尽可能快地优化这一代码,但第二阶段的所需时间要远多于单个90Hz帧。小幅度的移动看上去和感觉上近乎是立即执行,而更大幅度的操作则需要数秒时间。时间与正在移动的数量成正比。
当第二阶段超过1秒的时候,我们将显示Medium标志的动画,以说明操作需要一定的时间,而Medium不接受任何新的指令。我们将其称为“hourglass hands(沙漏手)”,因为这类似于Windows的沙漏标志或OSX的旋转指针。
你可以想象,你正在通过Move Tool告诉计算机一系列的指令。当你按下扳机键的时候,你正在告诉电脑“让我告诉你我想要你做什么”;当你释放扳机键时,你正在告诉计算机“现在为我生成结果”。当你告诉计算机你希望它为你做什么的时候,你能够实时在VR中使用双手是关键;但当你告诉计算机生成结果时,即使等待几秒钟也不会造成太大的影响。只要你的沉浸感不受干扰(眼睛接收90Hz的帧,系统能够继续精确追踪你的头部和手部运动 ),这一切都可以接受,因为你的虚拟现实幻觉不会遭到破坏。
Medium中的音效设计强化了正在发生的事情。当你按下扳机键并开始一个移动操作时,我们会播放一个弱拍音效;当你释放扳机键并完成移动操作时,我们会播放一个强拍音效。当第二阶段完成时,我们会播放最后的“叮”音效。这种音效设计能够有效告诉你计算机正在做什么。桌面端的内容创作应用很少使用音效,但对于虚拟现实应用而言,音效是沉浸感的一个重要组成部分。
显示沙漏手和阻挡用户输入的做法借鉴了桌面GUI应用。如果一切都足够迅速,我们将不需要这样做,而这是最理想的情形。但对VR应用中的冗长操作而言,这是一种切实可行的手段。
于1968年发布的论文《Response Time in Man-Computer Conversational Transactions》中写道,100毫秒或以下的操作将令人感觉是实时发生;1秒是不影响用户思路的界限;10秒是保持用户注意力的界限。对于虚拟现实世界中的临场感,Medium生成新一帧的所需时间需要靠近10毫秒。Move Tool能够符合这一系列的界限:第一阶段运行在VR帧率之下;第二阶段在1秒内结束,或者如果超过1秒,我们就会显示沙漏手。
2. 异步雕刻操作
VR模拟必须每90Hz或约10毫秒产生新的一帧,但Medium中的许多操作都比生成10毫秒帧需要花费更长的时间。答案?这当然是我们在异步运行的线程上计算这些冗长的操作。这是另一个能够为所有VR应用提供帮助的解决方案。
当你在Meidum中添加新的黏土时,在完成操作和显示结果之前通常会出现数十毫秒的延迟。但由于每90Hz将提供新的一帧,所以你的头部和手部会实时移动。只要头部和双手实时移动,你就不会注意到雕刻操作出现延迟。虚拟现实技术要求几乎是即时对头部和手部运动作出响应,但应用程序的结果仍然可以以较低的频率运行。
想象一下你正在使用自己最喜欢的桌面应用:在现实世界中,你的眼睛会从现实世界中接收到稳定的光子流,但计算机本身可能以更低的频率在平面屏幕上生成帧。这正是我们在Medium中的做法,也是我们可以把性能要求苛刻的3D内容创建带到实时VR应用的解决方案。
这类似于电脑屏幕上的鼠标光标。你期望鼠标光标可以立即响应你的手部操作,但你不一定期望应用程序能以相同的速度运行。
在幕后,Medium几乎像是两个不同的程序。一个程序负责雕刻和网格处理,而另一个程序则负责所有的渲染。雕刻和网格操作不会以VR帧率执行,但渲染需要。
部分帧在渲染时会下降到90Hz。对于这些帧,Medium将依靠于异步时间扭曲和异步空间扭曲来流畅地Rift提供新影像。
从下面你可以看到Medium的应用内分析工具。顶端的橙色条是每帧的时间,而你可以看到其相当稳定。视频中出现了多次移动操作,而每一个都需要数帧才能完成。有4个CPU线程正在进行中,以蓝色/紫色条显示。最顶端的线程是主线程,其正在持续地生成帧;后三个线程则在执行移动工具任务,与主线程异步运行,并需要数帧才能完成。它们不会影响整体的帧时间。
Medium使用单个CPU线程进行渲染,而这产生了供GPU使用的OpenGL指令。GPU渲染供Rift头显显示的立体影像。这两个线程每10毫秒将产生一个影像。
其余的CPU硬件线程执行雕刻操作和其他较低优先级的任务,如视频记录,在后台加载资源等等。雕刻操作可以在所有可用线程中并行工作,而且我们使用英特尔的ISPC编译器来为性能密集型代码生成SSE4和AVX2代码。
雕刻线程和主线程通过producer/consumer FIFO相互连接。由于新的网格数据是由雕刻线程生成,因此将其放入FIFO中。主线程花费最多两毫秒从该FIFO中复制数据,并为GPU做好准备。一旦经过两毫秒,我们就停止从FIFO中复制数据,然后继续渲染。我们在CPU帧时间预算中包含了两毫秒,以避免在更新数据时出现故障。当FIFO变满时,雕刻线程将停止,并等待主线程从FIFO中使用数据。这可以平衡工具操作的延迟,从而保持一致的帧率。
我们目前使用CPU来负责雕刻和网格任务。GPU可以更快完成相关任务,但GPU已经被渲染占用,特别是对我们最低规格的设备而言。即便存在,最低规格GPU上的空闲时间也是相当少。因此,尽管GPU在这方面可以轻松击败CPU,但毕竟CPU拥有更多的可用资源。也就是说,我们正在研究让GPU负责更多的雕刻任务,同时仔细观察,并确保我们不会影响帧速率。
确保异步雕刻操作的延迟不会变得太长非常重要。例如,如果你按下扳机键来添加黏土,但半秒后仍然没有任何东西显示,这就会令人感到沮丧。当延迟时间过长时,应用程序就会感觉迟缓。即使应用以90Hz显示帧,这种迟缓也会导致用户感到疲劳。我们正在不断调整Medium的操作,希望尽可能提高其处理速度,但没必要追求异步操作在10毫秒的框架内完成。
3. 总结
这是关于Move Tool系列文章的最后一篇博文。在整个系列中,我们介绍了如何使用Touch控制器创建位移场;我们是如何将位移场应用于3D对象;讨论我们创建的三个原型;Medium是如何将三角网格转换为有向距离场(signed distance field,SDF),而这将如何为其他类型的雕刻操作提供帮助;以及如何异步安排对性能要求巨大的操作。
我们希望这是有用的信息,可以帮助你设计和开发自己的VR应用程序。