VR优化延迟的方法(下)

继续上次的介绍,我们接着讲Timewarp的内容

Timewarp

了解过延迟渲染的人应该都知道, 我们可以利用ZBuffer的深度数据, 逆向推导出屏幕上每个像素的世界坐标。

这就意味着, 我们可以把所有像素变换到世界空间, 再根据新的摄像机位置, 重新计算每个像素的屏幕坐标, 生成一幅新的图像:

可以看到之前被遮挡区域的像素是缺失的, 因为我们的摄像机位置变化了. 那如果摄像机位置不变, 仅仅是朝向变了呢? 这样就不存在像素可见性的变化了:

Timewarp正是利用了这个特性, 在保证位置不变的情况下, 把渲染完的画面根据最新获取的传感器朝向信息计算出一帧新的画面, 再提交到显示屏. 由于角度变化非常小, 所以边缘不会出大面积的像素缺失情况.

Oculus的Demo中可以停止渲染新的画面, 完全由单帧图像计算出各个朝向的新画面:

也就是说, 只要角度变化不是非常大(上图为了演示效果偏转的角度很大了), 可以通过这项技术”凭空渲染”出下一帧的图像, SONY的PSVR正是利用这一点, 把60FPS的画面Reproject成了120FPS.

Timewarp只能处理头部转向, 不能处理头部移动的情况, 而且一旦错过了垂直同步的时机, 一样需要等待下一次垂直同步才能显示出来. 那能不能在每次垂直同步之前, 强制进行一次Timewarp呢? 那就需要驱动来开个后门了…

驱动层面的优化

假设垂直同步时, 当前帧还没有渲染完毕, 这时如果要进行Timewarp的话, 就需要驱动提供一种高优先级的异步调用, 这就是异步Timewarp的由来: Timewarp操作与场景渲染并行执行, 如果没有新的渲染画面, 就继续使用上一帧的画面进行Timewarp.

这可以在一定程度上补偿FPS不达标造成的延迟问题, GearVR中正是应用了这项技术, 保证了手机VR的体验.
当然, PC上使用项技术还是有一些限制:

必须是Fermi, Kepler, Maxwell(或更新)核心的GPU
GPU是以DrawCall为单位调度的, 所以耗时太长的DrawCall是插入不了Timewarp绘制操作的
需要最新的Oculus和NVIDIA驱动支持
异步Timewarp并不是说FPS低于标准还能流畅跑, 这只是一种补救措施, 所以优化仍然要好好做-_-

驱动方面还有一些其它的优化空间, 比如强制提交渲染队列:

如果驱动中缓存了3帧, 那延迟优化就白做了…

另外就是大家耳熟能详的Back Buffer(Double Buffer Rendering), 其实也会增加一点延迟, 不如省掉这一步, 即Front Buffer Rendering, 或者叫Direct Mode:

标签: vr

?>