时间扭曲与异步重投影
Timewarp & Asynchronous Reprojection
VR 中即使追踪完美,生成一帧仍需时间;掉帧会造成抖动 (judder)。厂商提供基于图像的补偿:只修正头部旋转的二维时间扭曲 (timewarp)、利用深度做三维重投影的位置时间扭曲、外推缺失帧的空间扭曲 (spacewarp),并常以异步方式运行作为掉帧保险。配合晚期朝向扭曲、late latching 和 CPU/GPU 流水线(running start / adaptive queue ahead),在不掉帧的前提下进一步缩短动作到光子的延迟。
抖动(21.4.1 节)
VR 设备的刷新率范围为 45~120 FPS。图像没能及时送到合成器就是掉帧;对 Oculus Rift 早期首发游戏的分析显示约 5% 的帧被丢弃。掉帧会加重抖动——头显中眼睛相对显示运动时最明显的拖影与频闪瑕疵。像素在整帧内一直点亮会在视网膜上形成拖影;降低余辉 (persistence)(每帧像素点亮的时长)可减少拖影,但帧间变化大时会产生频闪,看到多个分离的图像。
sequenceDiagram participant G as CPU/GPU participant C as 合成器 G->>C: 第 1 帧及时完成, 显示 Note over G: 第 2 帧未及时完成 C->>C: 第 2 次刷新重复显示第 1 帧 G->>C: 第 2 帧完成, 在第 3 次刷新显示 Note over G: 第 3 帧的计算结果从未显示 G->>C: 第 4 帧及时完成, 显示
如上图(据书中图 21.12),一次延误会连锁导致重复帧和白白浪费的计算。
预测与时间扭曲
- 用户头部转动减速时预测会过冲,图像比显示时刻的实际朝向略超前;除角速度外再估计角加速度可改善预测。
- 掉帧时只能用上一帧图像。时间扭曲按最新预测对其做二维图像扭曲,只补偿头部姿态的旋转,比什么都不做好得多。GPU 是最快的执行者(相比 CPU、DSP),多数 GPU 不到半毫秒即可完成。旋转图像会让显示图像的黑边进入外围视野,可渲染比所需更大的图像,但实践中几乎察觉不到。
- 纯旋转扭曲的另一个优点是场景元素彼此一致:用户实际上处在一个环境天空盒中心,只改变视向。
- 间歇性掉帧造成的不稳定、不可预测的延迟似乎比稳定掉帧更快引起晕动症。为了更平稳,Valve 的交错重投影在检测到掉帧时把渲染降到 45 FPS、每隔一帧扭曲一次;PlayStation 上某版本 VR 刷新率 120 Hz,以 60 Hz 渲染并用重投影填补交替帧。
位置时间扭曲与其局限
只修正旋转并不总是足够:头部转动或倾斜时即使人不移动,眼睛位置也会变化,例如纯图像扭曲会使两眼间距看起来变窄。附近有物体或低头看有纹理的地面时,不补偿位置变化会导致迷失方向和不适。三维重投影(Oculus 称位置时间扭曲)利用每个像素的深度把像素投回世界、移动眼睛位置、再投影回屏幕。缺点:
- 开销大;眼睛移动后某些表面会进入或离开视野(立方体某个面变得可见,或前景相对背景的视差遮挡/揭示细节),算法要识别不同深度的物体并用局部图像扭曲填补空洞,可能产生去遮挡拖尾(远处细节在物体经过时看起来移动)。
- 透明无法处理,因为只知道一个表面的深度,例如影响粒子系统。
- 片元颜色基于旧位置计算,镜面高光和反射不会改变,表面位置即使完美修正,高光仍可能抖动。
- 基础版本无法补偿场景中物体自身的运动或动画(只知道位置不知道速度);用速度缓冲记录运动后,重投影也能对此进行调整。
异步扭曲
旋转与位置补偿常在独立的异步进程中运行(Valve:异步重投影;Oculus:异步时间扭曲、异步空间扭曲)。空间扭曲分析之前的帧外推缺失帧,考虑相机与头部平移、动画和手柄运动,不使用深度缓冲。外推图像与正常渲染同时独立计算;由于基于图像,耗时相当可预测,所以渲染来不及时通常已有重投影图像可用——不必决定是继续完成该帧还是改用扭曲,二者都做。硬件要求适中,主要是给性能较弱系统的辅助。
| 技术 | 擅长 | 不擅长 |
|---|---|---|
| 旋转时间扭曲 | 观看远处静态场景或图像时的头部旋转 | 位置变化、物体运动 |
| 位置重投影 | 附近的动画物体 | 去遮挡、透明、高光 |
二者互补;朝向变化引起的配准问题通常比位置平移严重得多,所以仅做旋转修正就有显著改善。
时序与流水线(21.4.2 节)
- 最好的建议仍是应用本身尽量不掉帧。
- 晚期朝向扭曲 (late orientation warping):照常获取姿态生成帧,在帧后期再取一次更新的预测,若与渲染时所用姿态不同就做一次旋转扭曲。扭曲通常不到半毫秒,往往值得;实践中多由合成器负责。
- late latching:用单独 CPU 线程周期性地把预测姿态写入 GPU 的私有缓冲,GPU 在扭曲前最后一刻读取最新值;局限是应用此时拿不到每只眼的视图矩阵(只有 GPU 有)。AMD 的 latest data latch 让 GPU 在需要时直接抓取最新姿态。
- 流水线:多 CPU 系统中 CPU 在一帧里做碰撞检测、路径规划等并为下一帧准备数据,GPU 渲染上一帧 CPU 准备好的内容;要有效,CPU 和 GPU 每帧的工作都应少于一帧时间。合成器常用栅栏 (fence) 判断 GPU 是否完成——它作为命令由应用发出,之前所有 GPU 调用执行完毕后被触发,也可用于判断资源何时不再被 GPU 使用。
- running start(Valve)/ adaptive queue ahead(Oculus):CPU 若等到图像显示后才开始为下一帧生成命令,驱动解释并提交命令期间 GPU 空闲可达 2 ms。做法是估计上一帧何时完成,并在此之前就提交命令,让 GPU 一完成上一帧就立即开工;这种技术可在任何系统上实现,多数 VR API 也提供按固定节奏释放应用开始下一帧的机制。
flowchart LR A["CPU: 帧 N 模拟与命令生成"] --> B["GPU: 渲染帧 N"] B --> C["合成器: 晚期朝向扭曲, 畸变, 显示"] A2["CPU: 帧 N+1"] --> B2["GPU: 渲染帧 N+1"] B --> B2 A --> A2
如上图,CPU 领先 GPU 一帧工作;running start 把 GPU 两帧之间的空隙转化为可用的渲染时间。
展望
研究者在探索用光线投射渲染 VR:它直接解决宽视场和镜头畸变等光栅化难题,与注视点渲染配合良好;还可以在滚动显示即将显示某些像素前才对其投射光线,使这部分延迟几乎为零。
出处
- realtime_rendering_4ed.pdf 第 21 章 Virtual and Augmented Reality