不对称视野常见问题
从 Unity 2018.1.b5 开始,Meta 与 Unity 开展紧密合作,在 Oculus Rift 上启用了不对称视野 (FOV) 渲染功能。不对称视野渲染是一种更高效的 VR 眼部纹理渲染方式,在测试中可将渲染效率提升 10% 左右。在接下来的几个月中,我们计划将不对称视野渲染设为 Unity 中的默认配置。
本主题回答了一些常见问题,并提供了有关在 Rift 上使用 Unity 进行不对称视野渲染的一些最佳实践指导。
3D 场景通常使用具有对称视野的虚拟相机进行渲染。相机表示的是从 3D 空间到 2D 空间(显示在屏幕上)的投影,由水平视野和垂直视野定义。Unity 将这些值显示为垂直视野值和宽高比,从中可以计算出投影的水平视野。重要的是,这种方法假设屏幕的中心也是投影的中心,并且在每个轴上从中心到每条边的距离都相等。
在不对称视野系统中,投影的四条边彼此独立。这有助于实现不对称投影,这种投影方式也可以偏离渲染目标的中心。
尽管对称视野可以仅用两个值来表示,但不对称投影需要借助四个参数(如 LeftFov/RightFov/TopFov/DownFov)来控制投影矩阵中的视野。
为什么要在 Oculus Rift 上使用不对称视野?
采用不对称视野有助于提升 VR 头戴设备的使用体验,这是因为在这类设备中,透镜的中心点并不总是与屏幕的中心点重合。通过控制投影的中心(并将其与透镜匹配),我们可以生成能最大限度提升可见视野并减少锯齿和色差等伪影的图像。特别是对于可见视野的下部和外部,有更多的像素数据可供使用。
使用对称视野进行渲染时,GPU 必须填充比实际可见像素多得多的像素。由于透镜本身不对称,因此必须使用较大的渲染目标来确保覆盖住整个可见视野。这会浪费大量 GPU 功率,因为渲染目标中很大一部分像素都未用到。到目前为止,我们已经使用遮挡网格缩减了这些未使用像素的开销,但使用不对称视野则可以完全避免渲染额外像素。
在 Oculus Rift 上,对称视野渲染需要达到每只眼睛 1535x1776 的目标纹理。使用不对称视野,我们可以在不影响质量的前提下,将该纹理大小削减到每只眼睛 1344x1600,像素填充减少 22%。此外,这种方法还能够优化遮挡网格未能触及的方面,比如后处理、位图传输和解析成本。
尽管采用不对称视野主要节省的是 GPU 的消耗,但它也通过更紧密的视锥体剔除,节省了一些 CPU 资源,从而可以减少绘制调用。
我正在从对称视野切换到不对称视野。与对称视野相比,不对称视野是否会造成任何视觉损害?
不会。不对称视野不会改变显示屏上的可见像素,也不会改变投影的像素密度。它让我们能够裁剪已经超出观众视野的像素,因此与对称方法相比,视觉上应该没有明显变化。
没法保证。采用不对称视野可以改善剔除效果,减少带宽占用,降低像素渲染工作量。但是,对于在片段着色器或剔除成本上未出现瓶颈的应用,该方法没有任何优势。如果您的 GPU 在采用对称视野渲染时仍有剩余处理能力,那么进一步降低其工作负载将不会带来性能上的提升。
切换到不对称视野在大多数情况下都可以直接生效,但是也会带来一些副作用,特别是会影响图像效果。问题通常是由不对称视野投射屏幕坐标的方式不同而引起的。大多数问题可归结为两个具体差异:
首先,分配的视觉缓冲区的大小和视区大小发生了变化。这些变化是实现相同可见像素密度(Rift 上每个显示像素对应 1 个纹素)的必要。
- 在对称视野模式下,每个视觉缓冲区为 1536x1776。
在不对称视野模式下,每个视觉缓冲区为 1344x1600。
这可能会影响预期将特定 UV 值映射到像素的效果。
其次,投影中心可能不同。无论您使用的是非对称还是对称视野,标准化设备坐标 (NDC) 空间始终为[-1, -1, 0] -> [1, 1, 1](根据 DirectX 约定),屏幕中心始终位于 [0, 0, 深度]。然而,在不对称视野下,投影中心不再与屏幕中心重合,而使用偏移值。这使得非对称投影矩阵成为偏离中心的投影矩阵。
为了解决这个问题,您需要确定图像效果的中心对齐位置。如果您希望它位于视区中心,则可以使用 [0, 0, 深度] 的标准化设备坐标。如果您希望中心位于投影中心,那么使用此标准化设备坐标空间的中心是不够的。
幸好,计算非对称矩阵的投影中心并不复杂:
ProjectionMatrix * (0, 0, zNear, 1)
Unity 遵循 OpenGL 约定,因此请使用:
确定图像效果中心的位置是一个需要针对每个具体效果单独考虑的问题。以下方的渐晕效果为例,将渐晕与投影中心对齐是合理的做法(因为投影中心就是您直视前方时所看到的位置),但对于另一种效果,可能就需要将其与屏幕中心对齐。
我们可以借助此示例来展示需要针对不对称视野进行修复的图像效果是什么样的。在启用不对称视野之前,投影中心就在屏幕中心。如果您直视,就会看到最亮的像素。在启用不对称视野后,投影中心不再是最亮的像素,如果不加以调整,着色器效果看起来就会有问题。
渐晕着色器伪代码:
float pixelIntensity = 1.0 - dot(screenUV * 2.0 - 1.0, screenUV * 2.0 - 1.0) * intensity