中EN
概念页

VR 立体渲染优化

VR Stereo Rendering Optimization

VR 每帧要为两只眼渲染,并经合成器做镜头畸变与色差校正。本页讲厂商 SDK/API 的帧流程与内建优化(分层合成、隐藏区域网格、裁剪过的畸变网格),立体渲染如何避免工作量翻倍(合并视锥剔除、实例化、多视图扩展、多 GPU 广播、远景单目渲染),以及利用光学和人眼特性减少外围像素着色的技术:多分辨率着色、镜头匹配着色、径向密度遮罩、固定注视点渲染与注视点渲染。

始终使用厂商 SDK(21.3 节)

除非有极好的理由,始终使用系统提供方的 SDK 与 API。比如你可能认为自己的畸变着色器更快、看起来差不多,但可能导致严重不适,不经大量测试无从得知;为此所有主流 API 都已移除应用控制的畸变——正确显示 VR 是系统级任务。

flowchart LR
  A["估计本帧显示时刻"] --> B["按预计延迟向 API 查询每只眼的预测姿态"]
  B --> C["渲染两个目标, 或一个分成两视图的目标"]
  C --> D["作为纹理提交给合成器, 可附加 HUD 等图层"]
  D --> E["合成器: 畸变, 色差校正, 图层合成后显示"]

如上图。OpenVR 还需要知道用户站立还是坐着,这影响原点(追踪区域中心或头部位置)。合成器可合成多个不同分辨率和格式的图层,例如单目 HUD 作为单独图层叠在每只眼的视图上;这使得可以动态降低三维场景图层分辨率以节省渲染时间,同时保持其他图层的高质量。Oculus 并不先合成再校正,而是先分别校正每个图层再合成:每层按自身分辨率扭曲,例如文字的重采样和过滤只针对文字内容,质量更好。

隐藏区域网格与畸变网格

  • 隐藏区域网格 (hidden area mesh):人眼视场近似圆形,图像四角外围的像素虽然会显示却几乎察觉不到。渲染开始时先把一张网格写入模板缓冲作为遮罩,或写在 z-buffer 最前面,后续片元在这些区域被提前丢弃。HTC Vive 上约减少 17% 填充率;双眼图像拼接处被扭曲变换移除的中间条带也可以一并遮掉。
  • 畸变扭曲:光线投射可按波长精确重映射,但多数硬件不现实;全屏四边形在像素着色器中逐像素求畸变方程也较贵。更高效的是把渲染图像贴到三角形网格上:网格每个三角形渲染一次,但每个像素用三组 (u, v) 分别采样红绿蓝通道,以校正色差。
  • 规则网格既可以放在渲染图像上扭曲到显示图像,也可以反过来。把网格放在显示图像上、只调整顶点纹理坐标扭曲回渲染图像的好处是不会出现细长三角形,生成的 2×2 quad 更少。典型网格每只眼 48×48 个四边形,纹理坐标用逐通道的显示到渲染变换预先算好存在网格中,着色时无需复杂变换;可用 GPU 各向异性采样得到清晰图像。把网格裁剪到只覆盖可见区域(画黑色三角形毫无意义),最终畸变 pass 开销约减少 15%。

立体渲染不是两倍工作(21.3.1 节)

阴影贴图生成、模拟和动画与视图无关;像素着色调用数不会翻倍,因为显示被两个视图平分;后处理与分辨率相关,开销也不变。真正翻倍的是视相关的顶点处理,以及 API 调用。

方法做法评价
合并视锥剔除用一个视锥包住双眼视锥;剔除后才取精确视图,所以需要安全边距,建议视场角加约 5 度简单有效
顺序渲染先完整渲染一只眼再另一只状态切换翻倍;分块渲染器频繁换视图和渲染目标性能很差
逐物体渲染两次每个物体中间切换相机变换API 绘制调用仍翻倍
几何着色器复制生成两个视图的三角形并发送到不同目标几何吞吐量降到三分之一甚至更低,实践中不用
实例化一次绘制调用画两份,用用户裁剪平面分开两眼比几何着色器快得多,无额外 GPU 支持时的好方案
命令列表重放为一只眼录制命令列表,改引用的常量缓冲为另一只眼的变换后重放节省 CPU
多视图扩展如 OpenGL ES 3.0 multi-view:几何只发送一次,渲染到两个或更多视图可在驱动中用实例化实现,或由 GPU 把每个三角形送到各视图;总能降低 API 开销,复杂实现还能提高纹理缓存效率、视无关属性只着色一次

多 GPU:AMD 和 NVIDIA 提供为 VR 调优的方案,两块 GPU 各渲染一只眼。CPU 用亲和掩码指定哪些 GPU 接收某个 API 调用(两眼不同的调用仍要调用两次);NVIDIA 的广播用一次绘制调用发给所有 GPU,用常量缓冲传不同的眼睛位置,CPU 开销几乎与单视图相同。合成器需要单幅图像时,用专门的子矩形传输命令在 1 ms 内把数据从一块 GPU 异步搬到另一块。两块 GPU 各自生成阴影缓冲虽然重复,但比并行化再传输更简单、通常更快。整体渲染提速约 30%~35%;已为单 GPU 调优的程序可把多余算力用于更多抗锯齿采样。

远景单目渲染(Palandri 与 Green,GearVR):立体视差对近处重要、远处可忽略。设一个垂直于视线的分隔平面(默认约 10 m),更近的不透明物体立体渲染,更远的用位于两个立体相机之间的单目相机渲染。先画立体视图,用两者深度缓冲的交集初始化单目渲染的 z-buffer 以减少过度绘制,再把远景合成到每个立体视图,透明内容最后对每个视图渲染。跨越分隔平面的物体需要额外一遍,但稳定节省约 25%,画质和深度感无损。

减少外围像素着色

由于光学畸变,渲染图像外围的像素密度更高(外围较大的渲染区域只对应较小的显示区域),而且用户多数时间看向中心,外围不那么重要。

  • 多分辨率着色(NVIDIA;AMD 称可变速率着色):把屏幕分成如 3×3 块,外围以较低分辨率渲染(例如边块减少 50% 像素、角块减少 75%),视场不变;共享边上通常最好保持相同分辨率。
  • 同时多投影 (SMP):Pascal 起支持,几何最多可经 16 个投影 × 2 个眼睛位置处理,网格可被复制 32 次而无应用侧额外开销;第二个眼睛位置必须是第一个沿 x 轴的偏移,每个投影可独立倾斜或旋转。
  • 镜头匹配着色:用 SMP 渲染四个平面倾斜的视锥,让中心像素密度更高、外围更低,比多分辨率着色过渡更平滑;缺点是泛光等效果需要重做才能正确显示。Unity 和 UE4 已集成。也有每只眼用最多 3×3 个视图进一步减少着色的研究,SMP 可同时作用于双眼。
  • 径向密度遮罩:应用层方法,外围以棋盘格方式隔一个 2×2 quad 不渲染,再用后处理从邻居重建缺失像素。对单块低端 GPU 尤其有价值;但若跳过和重建的开销太高就没有收益。Sony 伦敦工作室更进一步,越靠近边缘在每组 2×2 quad 中丢弃 1~3 个,每帧改变抖动模式,并用时间抗锯齿掩盖阶梯瑕疵,约节省 25% GPU 时间。
  • 固定注视点渲染(Vlachos):每只眼渲染两幅图——中心圆形区域和外围环形区域,外围用低分辨率,再合成并扭曲。代价是几何要送到四幅图,正好契合 GPU 多视图支持,也天然适合 2 或 4 块 GPU 分工。

注视点渲染(21.3.2 节)

中央凹 (fovea) 是视网膜上密布视锥细胞的小凹陷,视敏度最高。离中心前 30 度内大约每 2.5 度视敏度下降 50%,更远下降更陡。人眼双目视场水平约 114 度,第一代消费头显约 80~100 度。中央 20 度在 2016 年的头显上约占显示的 3.6%,预计 2020 年左右降至 2%,而显示分辨率可能提高一个数量级。

注视点渲染 (foveated rendering) 只在眼睛注视处以高分辨率和高质量渲染,其余处少花力气。难点:眼睛会动,例如扫视 (saccade) 速度可达每秒 900 度,即 90 FPS 下每帧可能 10 度,需要精确的眼动追踪硬件,而这是技术挑战;外围渲染"更大"的像素会加剧走样,可通过保持对比度、避免随时间剧烈变化让外围在感知上更可接受。

  1. realtime_rendering_4ed.pdf 第 21 章 Virtual and Augmented Reality

相关页面

图形学VR 与 AR 显示基础VR & AR Display Fundamentals虚拟现实 (VR) 完全替换用户所见的世界,增强现实 (AR) 把合成物体融入真实世界,二者常合称 XR。本页介绍与渲染相关的硬件与物理要素:追踪与显示设备、"动作到光子"延迟及其导致的模拟器晕动症、姿态预测、镜头光学畸变与色差的软件补偿、滚动与全局显示,以及立体视觉中的辐辏-调节冲突与瞳距。这些约束决定了 VR 渲染为何必须高帧率、低延迟并严格依赖厂商 SDK。图形学VR 渲染注意事项VR Rendering Considerations在单屏上效果良好的渲染技术,放到随头部移动的双目显示上可能失效甚至引起不适。本页汇总 RTR4 第 21.4 节列出的需要修改或避免的技术:HUD 深度、凹凸与视差贴图、公告板与天空盒、色调映射与屏幕空间效果、镜面高光视差、抗锯齿选择、色带、运动模糊与景深,以及混合现实中的光照匹配。核心原则:严格遵循厂商头部模型和投影矩阵,任何会让两眼图像难以融合或与前庭感觉冲突的效果都要谨慎。图形学时间扭曲与异步重投影Timewarp & Asynchronous ReprojectionVR 中即使追踪完美,生成一帧仍需时间;掉帧会造成抖动 (judder)。厂商提供基于图像的补偿:只修正头部旋转的二维时间扭曲 (timewarp)、利用深度做三维重投影的位置时间扭曲、外推缺失帧的空间扭曲 (spacewarp),并常以异步方式运行作为掉帧保险。配合晚期朝向扭曲、late latching 和 CPU/GPU 流水线(running start / adaptive queue ahead),在不掉帧的前提下进一步缩短动作到光子的延迟。图形学剔除技术Culling Techniques剔除 (culling) 是在渲染前尽快去掉对最终图像没有贡献的部分。本页讲几何类剔除:背面剔除(含成簇背面剔除与法线锥)、视锥剔除(层次化、平面掩码)、室内场景的入口剔除,以及牺牲质量换速度的细节剔除和小三角形剔除。更复杂的遮挡剔除见 遮挡剔除。图形学绘制调用与状态切换优化Draw Calls & State Change Optimization调用图形 API 的开销主要在 CPU 端的驱动里:状态切换昂贵,每次绘制调用有固定开销,大量小批次会让 GPU"饿死"。对策是:合理放置缓冲;按状态代价排序分组;共享纹理和着色器;合并网格和实例化以减少调用;并用一个整数排序键同时兼顾状态分组与前后排序。图形学曲面细分与几何着色器Tessellation & Geometry Shader曲面细分、几何着色器和流输出是顶点着色器之后的三个可选阶段。曲面细分把曲面描述按需生成合适数量的三角形;几何着色器能把图元变成别的图元,但效率不好、实际用得少;流输出把处理后的顶点写回内存以便复用。图形学像素与帧缓冲优化Pixel & Framebuffer Optimization需要着色的像素通常远多于顶点,所以像素处理优化往往最划算。核心手段:保证占用率以隐藏纹理延迟、按距离切换着色器 LOD、利用 early-z 并通过从前往后排序或 z-prepass 减少过度绘制、缩小帧缓冲每像素存储(色度子采样、YCoCg 棋盘),以及只在需要时开启混合、避免 GPU 回读。几何与光栅化阶段的常用优化也一并列出。图形学纹理过滤与 MipmapTexture Filtering & Mipmap纹理在屏幕上被放大时需要插值,被缩小时一个像素覆盖许多纹素,必须预先滤波才能避免混叠。放大用最近邻、双线性或双三次;缩小的主流方案是 mipmap + 三线性插值,斜视角下用各向异性过滤减少过度模糊。注意:过滤纹理值只在输入与着色结果线性相关时等价于过滤最终颜色。图形学GPU 架构案例GPU Architecture Case StudiesRTR4 第 23.10 节剖析三种架构:面向移动设备、以能效为先的 sort-middle 分块架构 ARM Mali G71 Bifrost;NVIDIA Pascal(GTX 1080)的 SM/TPC/GPC 层级与介于 sort-middle 和 sort-last fragment 之间的 tiled caching;AMD GCN Vega 的计算单元、异步计算引擎、DSBR 与 HBCC。硬件厂商通过对尚未制造的 GPU 做大量参数化仿真来决定 MP 数量、缓存、光栅引擎、ROP 数等——各种单元数量的原因归根结底是"这样效果最好"。综合帧时间预算与渲染性能Frame Budget & Rendering Performance本页把 wiki 中分散在 RTR4 第 18~23 章的性能知识串成一条线:一帧的时间预算由最慢的管线阶段决定,先用毫秒帧时间度量并定位瓶颈,再按瓶颈所在位置——CPU/驱动、几何、像素、带宽/内存——选用对应手段;最后从 GPU 硬件机制(占用率、HiZ/early-z、压缩、分块架构)理解这些手段为何有效。各结论的细节与出处见所链接的概念页。

输入关键词开始搜索

滚轮或双指缩放 · 拖动平移 · 双击放大 / 还原