研发实战:Oculus发布ASW 2.0开发者指南
有关ASW 2.0的更多技术细节
(映维网 2019年08月13日)Oculus在2018年4月发布了涵盖Asynchronous Spacewarp 1.0(异步空间扭曲;ASW)和Positional Timewarp(定位时间扭曲;PTW)的ASW 2.0,并旨在实现更高质量和更低延迟的VR体验。
最近Oculus再次介绍了有关ASW 2.0的更多技术细节,以及如何确保你的VR应用能够兼容ASW 2.0的技巧。下面是映维网的具体整理:
1. 从ASW到PTW
当Oculus在2016年带来了ATW(Asynchronous Timewarp;异步时间扭曲)之后,发布PTW是合乎逻辑的下一步,只是当时Oculus发现了一个充满前景的解决方案。这显然是ASW。ASW可以在时间方面平滑各种运动线索(如动画和头显追踪),而PTW只能在时间方面校正头显追踪。从这个意义来说,ASW看起来像是一种升级版PTW,但Oculus很快意识到PTW存在ASW尚未完全能够实现的优势。
Oculus在2017年推出了Oculus Dash,以及允许VR应用程序提供深度缓冲的选项,从而支持其利用名为ovrLayerEyeFovDepth的新图层类型来帮助深度合成。如下面的截图所示,深度缓冲区用于在VR应用程序的内容穿插Oculus Dash内容时应用X射线效果。同时,Oculus的Engine-Integrations团队开始在Unreal 4和Unity中使用这种图层类型。
大多数VR应用程序都经过优化并能够以本机头显刷新率运行,但只是在单独运行时是这样。当Oculus Dash出现并使得CPU或GPU超过其性能预算时,这可能导致应用程序出现丢帧。在这种情况下,Oculus运行时系统将自动将ASW应用于VR应用程序。但由于ASW在任何给定时间内仅限于一个合成器层,如果Oculus Dash和VR应用程序无法同时以所述速率运行,将需要一种不依赖ASW并能平滑Oculus Dash内容移动的方法。这正是PTW有发挥作用的时候。当Oculus为Oculus Dash打磨PTW时,Oculus继续优化ASW,令其能够以与PTW配合使用,并且进一步提高时间稳定性。这就是ASW 2.0的诞生过程。
2. ASW 1.0 vs 2.0
下面这个视频是ASW 1.0和ASW 2.0应用至《Robo Recall》时的效果对比。白色箭头是调试指南,其说明了每个图块的计算运动矢量,并由ASW用于内容运动扭曲。
所述视频帮助说明了两者的主要差异。对于ASW 1.0,请注意布告板的视差(由于头部运动)仅由ASW补偿。由于ASW 2.0能够利用PTW,相同的视差将注册最小的ASW校正,因为它主要由PTW处理。如预期一样,旋转风扇叶片依然由ASW校正,而椅子和几何边缘的微小校正则主要归功于在PTW之后由ASW运动矢量进行的去除遮挡和视图相关着色。
3. 结合ASW和PTW
为了进一步理解ASW是如何与PTW结合使用,我们首先需要明白ASW的流程。以下是Oculus运行时使用ASW所需步骤的细分:
- ASW捕获由合焦VR应用程序提交的先前和当前ovrLayerEyeFov帧的纹理。
- 通过时间扭曲前一帧,ASW生成“pre-warp frame”并使用当前帧的姿态。
- ASW将当前帧和pre-warp frame纹理转换为GPU视频编码器友好型资源。
- ASW将两个帧纹理发送到GPU视频编码器以进行对应分析。
- ASW从GPU视频编码器输出采集“运动矢量”。
- ASW后处理并转换运动矢量以进行帧外推。
- ASW将内容打包并注入至合成器层,仿佛它是来自于VR应用程序。
- Compositor像以往一样利用ASW注入的ovrLayerEyeFov图层内容进行时间扭曲和变形。
如步骤#2和#8所示,我们依赖于时间扭曲(Timewarp;TW)。在最初的ASW实现中,由于缺乏用于PTW的深度缓冲区,所以当时使用的TW重投影技术是Orientation Timewarp(方向时间扭曲;OTW)。但随着越来越多的VR应用程序开始提供深度缓冲区,可以应用PTW。诀窍是确保在上述两个步骤中的TW-重投影技术(无论是OTW还是PTW)是同一类型。这确保了在ASW或TW中能够校正头显移动重投影,但不是同时在两个地方校正,因为这会导致视觉伪影。当深度不可用时(即VR应用程序提交ovrLayerEyeFov而非ovrLayerEyeFovDepth),Oculus运行时会自动回到ASW 1.0。
4. PTW风格
PTW能够以多种不同的方式实现。Oculus的要求中有几个非常重要的点:
- 为PTW使用尽可能少的GPU周期,从而允许VR应用程序最大化其GPU使用率。
- 无需处理与上一视图位置的显著重投影偏差,因为每个新的VR-app渲染将使用非常接近前一个的新头显目标姿态。
- PTW的每次重投影结果仅在瞬间可见(通常小于20毫秒),因为VR应用程序以非常高的速率提供新图像。
熟悉实时图形知识的人士应该知道类似的技术,例如视差映射、视差遮挡映射、高度图光栅化等等。在大多数技术中,着色器将对高度图纹理进行采样,从而确定纹理样本查找的补偿量。PTW所使用的深度缓冲区同时可以认为是旋转到面向camera的高度图。
为了评估各种权衡,Oculus多年来尝试了众多不同的PTW技术。诸如视差-遮挡映射之类的技术更精确,但需要花费更多的GPU周期。我们选择的技术类似于稀疏-视差-映射技术,因为它有助于我们实现上述所有要点。与OTW相比,我们的PTW开销非常低,同时足以帮助解决由于头显转换而在OTW中看到的抖动伪影。在大多数情况下,PTW与OTW的GPU性能损失将在帧定时噪点中丢失。
5. 深度缓冲区
PTW主要依赖于深度缓冲区,尽管网络存在大量关于深度缓冲区的信息,但下面不妨再深入挖掘一下。深度缓冲区在实时渲染中发挥着重要作用,随着时间的推移和GPU性能优化的结合,它们的内部表示变得更加复杂。但在其核心,深度缓冲区是由GPU在光栅化3D场景时所生成的值的2D阵列,其中缓冲区中的每个元素存储对应颜色缓冲元素的深度值。由于深度缓冲区通常作为光栅化的副产品生成并供GPU用于遮挡剔除,所以生成深度缓冲区的成本是主要考量因素。对于PTW,在渲染VR应用程序时并生成深度缓冲区后,可以预期VR应用程序会将内容作为ovrLayerEyeFovDepth图层的一部分提交。从那时起,Oculus运行时合成器在Timewarp&Distortion阶段处理剩余的PTW重投影。
深度缓冲区可以以浮点或标准化整数格式保持值,但这种原始值不直接表示给定像素的距离。相反,深度值是在光栅化期间利用投影矩阵进行计算。投影矩阵会将每个顶点和像素转换成最终的深度值并存储在存储器中。对于投影矩阵能够将线性距离变换为可以存储在深度缓冲器中的值,这可以视为有效映射线性距离值,并为更接近于用户的元素带来更高精度的方式。
不同的内容可以调用不同的映射方案和剪切边界。例如,早期是采用基于整数的低精度深度格式,camera平截头体的近剪切平面和远剪切平面的距离是令人感到沮丧的重要原因。在最近几年里出现了浮点值,投影矩阵可以将远剪切平面映射到无限远。线性距离到最终深度值的映射使得高精度浮点能够派上用场。请记住,一旦给定顶点进行了变换并栅格化为三角形,GPU将自动剪切投影范围和平截头体之外的元素。
由于这一切的考虑,Oculus在Oculus Rift PC SDK中创建了辅助函数,而应用开发者可以在创建投影矩阵时予以使用。Oculus同时提供了允许通过常用方法来创建投影矩阵的枚举。以下是SDK中OVR_CAPI_Util.h文件的摘录,其说明了用于指定投影矩阵的修饰符。有关每个枚举的说明,请参阅PC SDK文档。
enum ovrProjectionModifier {
ovrProjection_LeftHanded,
ovrProjection_FarLessThanNear,
ovrProjection_FarClipAtInfinity,
ovrProjection_ClipRangeOpenGL
};
对于PTW,Oculus感兴趣的是追踪空间units中每个像素到渲染camera的距离。如果VR应用程序仅提交深度缓冲区而不包括其他元数据,Oculus运行时系统将没有足够的信息来重新计算像素的原始线性距离。到目前为止,我们不难看出VR-app使用的投影矩阵是PTW算法所需的信息之一。但PTW不需要整个矩阵,只需要与渲染元素的Z和W坐标有关的部分。为了从投影矩阵中提取必要的组件,SDK同时提供了一个可以整齐地打包称为ovrTimewarpProjectionDesc,以及一个名为ovrTimewarpProjectionDesc_FromProjection的辅助函数的最小信息量的结构。如果开发者不希望将自己的矩阵格式转换为SDK格式,你可以查看函数的实现,并简单地提取必要的组件。
另一个需要的数据是,VR应用程序用于渲染units的世界和视图比例。在某些渲染引擎中,world-unit转换比例不是作为投影矩阵的一部分进行处理。这需要特别注意,因为游戏引擎的1 unit是1厘米,而Oculus Rift PC SDK总是以米为单位处理unit,即1 unit是1米。当所述引擎渲染距离为4米的平面时,应用于深度缓冲区的投影矩阵倒数将产生400个unit的距离。但在PTW算法中,我们只希望计算4个unit。所以在这个示例中,除非投影矩阵中已经获得了这个比例系数,否则将向Oculus运行时提供0.01的渲染比例系数。VR应用程序可以使用ovrViewScaleDesc struct单独将这个值提交给SDK。
6. API局限性
当前的深度提交API存在一定的限制,比如说:
- FovDepth层中提交的深度和颜色缓冲区需要使用匹配的分辨率。
- 不支持深度缓冲区的“color”格式,例如OVR_FORMAT_R32_FLOAT。
- 不包含多重采样(MSAA)的OVR_FORMAT_D32_FLOAT(即MSAA)是目前最佳的方式。其他格式可能会导致Oculus运行时系统出现资源复制或解析。
7. 总结和最后的想法
为了将PTW用于一个给定的VR应用程序,Oculus Rift PC运行时需要开发者采取下面的步骤:
- 将深度缓冲区栅格化或复制到ovrLayerEyeFovDepth图层的DepthTexture交换链中。
- 在图层的ProjectionDesc数据member中提供投影矩阵参数。
- 在提交图层时,使用ovrViewScaleDesc struct提供HmdSpaceToWorldScaleInMeters参数。
值得一提的是,如果你选择的是Unreal 4或Unity,最新的Oculus引擎集成已经提供了将深度缓冲区提交到Oculus Rift PC运行时系统的必要工具。
你同时可以查看已更新的OculusRoomTiny和OculusWorldDemo样本,并了解提交深度缓冲区所需的步骤。OculusWorldDemo同时在菜单中提供了其他工具(可通过“Tab”键进行切换),其可以帮助了解PTW是如何提供帮助。你只需导航到Timewarp菜单,增加帧时间以降低帧速率,然后在Layers→Main Layer选项下打开/关闭深度提交即可。