
这次更新为 Axmol 带来了真正基于 OpenXR 的 VR 渲染路径。过去的 generic VR renderer 更适合本地预览和调试双眼渲染效果,但它并不连接真实头显运行时。现在,Axmol 可以创建 OpenXR session,渲染到运行时提供的 swapchain,提交双眼 projection layer,并把手柄输入接回引擎事件系统。
从 Renderer 到 Compositor
这次重构把场景渲染扩展点从 SceneRenderer 调整为 SceneCompositor。Compositor 负责和一帧画面绑定的场景呈现策略:它可以在逻辑更新前轮询运行时事件,也可以按普通方式渲染场景,或者把同一个场景按多视图、多目标、多运行时 swapchain 的方式组合输出。
默认 SceneCompositor 保持普通渲染行为。VR 现在拆成两条路径:
- VRPreviewSceneCompositor:不依赖 XR runtime,用于本地双眼预览、畸变网格和调试。
- VRSceneCompositor:基于 OpenXR 的真实 HMD 渲染路径。
这样预览路径仍然轻量,产品级 VR 路径则可以按运行时要求处理 frame timing、swapchain 和控制器输入。
OpenXR 路径做了什么
新增的 OpenXRDriver 驱动 OpenXR 帧管线:
- OpenXR instance、system、session 和 local space。
- 双眼 view configuration 和 swapchain。
- 每帧 xrWaitFrame、xrBeginFrame、xrEndFrame 流程。
- 把 OpenXR swapchain image 包装成当前 RHI 可渲染纹理。
- 手柄 action set、binding、pose、button、thumbstick 和 interaction profile。
VRSceneCompositor 则把这些运行时状态接入 Axmol 的帧循环:在 scheduler update 前同步 XR 事件和输入,根据 runtime 给出的 eye pose 和非对称投影矩阵渲染每只眼睛,绘制手柄射线,提交 GPU 命令,释放 swapchain image,最后提交 projection layer。
手柄射线接入 PointerEvent
OpenXR 手柄输入现在会进入两个层级。
如果需要 XR 原生语义,可以使用 XRInputEventListener 监听 button、axis、aim pose 和 grip pose。
如果要复用现有 UI 和场景交互,手柄 aim ray 也会桥接为 PointerEvent。现在 PointerEvent 可以携带:
- PointerType::Controller
- 当前和上一帧 3D ray
- 世界坐标中的 PointerHitResult
这意味着已有的 pointer listener 可以参与 VR 交互;自定义节点也可以覆写 Node::onPointerHitTest() 来支持射线拾取。Widget、ScrollView、Menu、Terrain 以及相关测试已经适配了这条路径。
RHI 层的支撑
OpenXR swapchain image 由运行时拥有,而不是由 Axmol 创建。为了渲染到这些图像,RHI 新增了 ExternalTextureDesc,用于包装外部 native texture。Renderer 也新增了只提交当前 GPU 命令、不 present 默认窗口 surface 的接口,方便 OpenXR compositor 在释放 swapchain image 前确保渲染工作已经提交。
对于 Vulkan,OpenXRVulkanInterop 实现了 VulkanInterop 抽象接口,通过 Application::registerVulkanInterop() 在引擎初始化阶段注入。GraphicsCore(原 DriverContext)在创建 Vulkan 设备时通过该接口向 OpenXR runtime 查询所需的 extension 和 runtime 选择的 physical device,核心 RHI 层不再依赖 OpenXR 头文件。
如何启用
CMake 开启:
-DAX_ENABLE_VR=ON
-DAX_ENABLE_OPENXR=ON
如果 OpenXR 使用 Vulkan,请在 applicationWillLaunch() 中调用:
void AppDelegate::applicationWillLaunch()
{
#ifdef AX_ENABLE_OPENXR
registerVulkanInterop();
#endif
}
然后安装对应 compositor:
#ifdef AX_ENABLE_OPENXR
renderView->setSceneCompositor(std::make_unique<ax::VRSceneCompositor>());
#else
renderView->setSceneCompositor(std::make_unique<ax::VRPreviewSceneCompositor>());
#endif
这是 Axmol VR 栈接入 OpenXR 的关键一步:真实运行时 frame timing、头显 swapchain、双眼 pose/projection,以及手柄输入都进入了引擎主路径。
平台说明:本 PR 仅在 Win32 desktop 上验证通过,Android 未经测试,不承诺兼容。


