本节摘要:XR 渲染管线和传统 3D 渲染最大的差异是"立体"——同一帧要渲染两次(左眼+右眼),还要在显示前对每只眼做反畸变。整条管线在 11.1ms(90Hz)内完成。本节拆开 XR 渲染管线的 8 个阶段,给出每个阶段的预算;再用一个 Shader 演示"注视点渲染"——把注视点附近 20% 区域做全分辨率,剩下 80% 降采样。
阅读完本节,你应当能够:
XR 渲染看起来"只是把 3D 画面投到屏幕上",但要解决 4 个非平凡问题:
这 4 个问题任何一个没解决,体验都会瞬间崩塌。
| 阶段 | 工作内容 | 典型耗时 |
|---|---|---|
| 1. 姿态采样 | 从 IMU/SLAM 读出头/眼 6DoF | <0.1ms |
| 2. 视锥裁剪 | 根据姿态裁剪掉画面外物体 | 0.2ms |
| 3. 立体渲染 | 同帧渲染左眼+右眼 | 4-6ms |
| 4. 反畸变 | 把渲染好的图像做反向桶形畸变 | 0.5ms |
| 5. 注视点渲染 | 对中心 20% 做全分辨率,边缘降采样 | 已包含在 3 |
| 6. 合成 | 把虚拟画面 + 摄像头透视合成 | 0.3-0.5ms |
| 7. TimeWarp | 用最新姿态重新投影画面 | 0.3-0.5ms |
| 8. 显示 | 送面板显示 | 由硬件决定 |
加起来 5-7ms 是理想情况。剩下的 4-6ms 留给 CPU(物理、AI、脚本)和系统调度。
⚠️ 常见坑:把"渲染"和"显示"分开看。如果渲染完成时已经过了 11ms,下一帧 TimeWarp 也救不回来——画面会出现"卡顿+拖影"。
人的左右眼相距约 63mm。看同一物体时,左右眼图像有一个微小偏移——视差(Disparity)。大脑根据视差反推出物体的深度。XR 渲染就是模拟这个过程:
// Unity 立体渲染:每只眼一个 view matrix Matrix4x4 viewLeft = cameraLeft.worldToCameraMatrix; Matrix4x4 viewRight = cameraRight.worldToCameraMatrix;
两个 view matrix 的差异就是 IPD(约 0.064m)。IPD 是 XR 头显必须支持的可调参数——每个人的瞳距不同,固定 IPD 会让一部分用户疲劳。
透镜让边缘画面"拉宽",叫桶形畸变(Barrel Distortion)。XR 渲染要在送显示前对图像做反向桶形畸变:
// 反畸变 Shader half4 frag (Varyings input) : SV_Target { float2 uv = input.uv * 2.0 - 1.0; // 转到 [-1, 1] float2 distortedUV = uv * (1.0 + k * dot(uv, uv)); // 反向桶形 distortedUV = distortedUV * 0.5 + 0.5; return SAMPLE_TEXTURE(_MainTex, distortedUV); }
其中 k 是畸变系数,Quest 3 约 0.18,Vision Pro 约 0.12。没有这一步,画面边缘会糊+色散。
TimeWarp(时间扭曲):当 GPU 渲染完成时,用户头已经又转了一点。TimeWarp 用"渲染后到显示前"这 1-2ms 时间,用最新的头部姿态重新投影整个画面。
SpaceWarp(空间扭曲):当帧率掉到 60Hz 时,SpaceWarp 在 TimeWarp 基础上再补一帧——用前后两帧的深度信息"猜"出中间那一帧。Meta Quest 3 的 90Hz 实际跑 45Hz 渲染 + SpaceWarp 补帧,可以省 50% GPU 负载。
Quest 3 / Vision Pro 都默认开启这两项。开发者只要保证渲染 45-60Hz 即可。
人眼中央凹的分辨率远高于周边——但全画面高分辨率是浪费。注视点渲染只对注视点附近 20% 区域做全分辨率,剩下 80% 降采样:
// 注视点渲染 API var foveationParams = new XrFoveationProfile() { FoveationLevel = XrFoveationLevel.High, VerticalOffset = 0.0f }; xrSession.SetFoveation(foveationParams);
这项技术让 Vision Pro 跑 4K×2 Micro-OLED 时实际 GPU 负载只增加 30%,而不是 100%。
💡 关键直觉:注视点渲染不是"硬件升级",是"算法降本"——它用算法把硬件压力从 100% 砍到 30%。这是 XR 行业的核心工程智慧。
// 启用注视点渲染(Unity 2022 LTS+) using UnityEngine.XR.OpenXR; var settings = OpenXRSettings.Instance; settings.eyeTracking = true; settings.foveatedRendering = FoveatedRenderingLevel.High;
跑起来后用 RenderDoc 抓帧,会看到:中心 20% 区域是 4K 分辨率,边缘是 1K 分辨率——但肉眼看不出差异。GPU 帧时间从 8ms 降到 5ms,省下的 3ms 可以用来做更多 AI/物理。
把 XR 渲染管线的 8 个阶段画成流水线——每个阶段的输入/输出和典型耗时一目了然。

下一节我们看第二个支柱:跟踪与 SLAM。