这次更新为 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()中调用:
voidAppDelegate::applicationWillLaunch(){#ifdefAX_ENABLE_OPENXRregisterVulkanInterop();#endif}然后安装对应 compositor:
#ifdefAX_ENABLE_OPENXRrenderView->setSceneCompositor(std::make_unique<ax::VRSceneCompositor>());#elserenderView->setSceneCompositor(std::make_unique<ax::VRPreviewSceneCompositor>());#endif这是 Axmol VR 栈接入 OpenXR 的关键一步:真实运行时 frame timing、头显 swapchain、双眼 pose/projection,以及手柄输入都进入了引擎主路径。
平台说明:本 PR 仅在 Win32 desktop 上验证通过,Android 未经测试,不承诺兼容。