使用MTVerseXR SDK实现VR串流

1、概述​

MTVerseXR SDK 是摩尔线程GPU加速的虚拟现实(VR)流媒体平台,专门用于从远程服务器流式传输基于标准OpenXR的应用程序。MTVerseXR可以通过Wi-Fi和USB流式将VR内容从Windows服务器流式传输到XR客户端设备, 使相对性能低的VR客户端可以使用高性能图形服务器的渲染能力。

2、环境准备​

MTVerseXR SDK包括服务器驱动程序、客户端SDK和示例客户端应用程序。Windows上运行的服务端和VR头盔内的应用程序共同实现了Windows系统(边缘云)的SteamVR与VR头盔客户端的连接。

2.1 MTVerseXR 服务器驱动​

运行平台要求

  • 系统:x86 CPU + Windows10

  • 显卡:摩尔线程MTT S80, MTT S70, 驱动程序 v240.50或更新版本

  • 软件:SteamVR

  • 基于OpenXR的Windows VR应用

2.2 MTVerseXR 客户端SDK​

客户端SDK目前只支持Android系统。包含头文件、Android so库文件和资源文件,通过AAR的方式提供。

3、服务器驱动安装和启动​

  1. 安装SteamVR:
    • 下载并安装Steam
    • 在Steam中安装SteamVR
  2. 安装运行时库
    • 下载并安装vc_redist.x64.exe
  3. 安装Vulkan驱动:
    • 依次运行 VulkanRT-1.3.261.1-Installer.exe 和 VulkanSDK-1.3.261.1-Installer.exe 安装Vulkan
    • 链接如下:
      https://sdk.lunarg.com/sdk/download/1.3.261.1/windows/VulkanRT-1.3.261.1-Installer.exe
      https://sdk.lunarg.com/sdk/download/1.3.261.1/windows/VulkanSDK-1.3.261.1-Installer.exe
  4. 安装 MTVerseXR驱动:
    • 以管理员权限运行 MTVerseXRSetup-v1.0.0.exe 安装程序;
    • 按照安装向导的步骤进行安装,在最后一页,记得勾选“注册驱动”。如果未勾选注册驱动,可以通过以管理员权限运行安装目录下的 driver_install.bat 文件来完成注册;
    • 重启计算机
  5. 启动SteamVR
    • 确认MTVerseXR驱动启用, 查看SteamVR 【设置】-【启动/关闭】-【管理加载项】-【MTXR_VHMD】选项是开启状态(如果【设置】页面没有【启动/关闭】,点击【设置】页面的左下角【高级设置】下方的【显示】)

4、客户端开发指南​

基于Client SDK 开发App的C++部分大致框架如下:

int main() {
 
   MySetupGLES3-2
   MySetupXRSession
 
   MySetupDeviceDesc(&ddesc);
   MySetupCallbacks(&callbacks);
   MySetupReceiverDesc(&rdesc, ddesc, callbacks)
 
   MTXRCreateReceiver();
   MTXRConnect();
 
   while (!*exiting*) {
      MyPlatformEventHandling();
      if (client_state < connected) {
         MyRenderConnectionProgress();
      }
      else if (client_state == connected) {
         UpdateTrackingState();
         MTXRFetchFrame()
         MTXRRenderFrame(framesFetched);
         MTXRReleaseFrame()
      }
      else {
         MyHandleDisconnect();
         exiting = true;
      }
   }
 
   MTXRDestroyReceiver()
}

请注意,此处的UpdateTrackingState是伪代码中更新位姿回调的占位符。在UpdateTrackingState中,可以处理头盔、手柄的位姿和手柄事件,保存最新的位姿信息,在回调中更新。

Java部分需要在Activity的onCreate中调用MTXRClient.init 初始化客户端SDK组件。
SDK同时提供了工具类MTXRServerDiscover和MTXRUSB。其中MTXRServerDiscover用于探测局域网中的MTVerseXR Server,MTXRUSB用于打开USB配件模式的文件描述句柄,具体参考示例代码。

4.1 引用SDK包​

在app的gradle中添加aar依赖。

手动或者使用gradle脚本解压aar文件后,在CMakeLists或者Android.mk中引用SDK的头文件和so文件。解压后头文件的路径为assets\include, so的路径为jni\arm64-v8a。

4.2 初始化​

Java部分的初始化:

  • 在App MainActivity的onCreate中调用 MTXRClient.init 完成。
protected void onCreate(Bundle savedInstanceState) {
    setContentView(R.layout.xr);
    // 初始化MTXRClient
    MTXRClient.init(getBaseContext());

    // do super first, as that sets up some native things.
    super.onCreate(savedInstanceState);

    boolean usMic = false;
    enableMicrophone(usMic);
    ……
}

C++部分初始化:

  1. OpenGLES 3.2上下文环境初始化(SDK目前仅支持OpenGLES环境下的显示,版本要求>=3.2);
  2. OpenXR Sessioin环境初始化(非必须通过OpenXR);
  3. 获取设备相关参数填充MTXRReceiverDesc的成员变量,包括:显示分辨率、刷新率、音频接收状态等;
  4. 设置MTXRClientCallbacks中需要的回调函数,包括GetTrackingState(必须实现以同步最新的位姿和手柄输入)和GetHapticCallback(手柄震动反馈);
  5. 调用MTXRCreateReceiver 创建Receiver对象,用于和服务器端通信的重要对象;
  6. 调用 MTXRConnect(Wifi连接)或者MTXRConnectUSB(USB连接) 连接服务器。
void XRScene::Start(const std::string& serverIp, int fd, bool enableMic) {
  m_desc.deviceDesc.posePollFreq = 0;

  m_desc.clientCallbacks.GetTrackingState = [](void *context, MTXRVRTrackingState *trackingState) {
    reinterpret_cast<XRScene*>(context)->GetTrackingState(trackingState);
  };
  m_desc.clientCallbacks.ReceiveMicrophoneData = NULL;
  m_desc.clientCallbacks.GetHapticCallback = [](void* context, MTXRHapticFeedback *haptic) {
      XRScene* that = reinterpret_cast<XRScene*>(context);
      if (NULL != that->m_haptic_callback && NULL != that->m_context) {
        that->m_haptic_callback(that->m_context, haptic);
      }
  };
  ……
  m_desc.deviceDesc.receiveAudio = true;
  m_desc.clientContext = this;
  m_desc.requestedVersion = MTXR_VERSION_DWORD;
  m_desc.deviceDesc.sendAudio = enableMic;
  if (enableMic) {
    m_desc.clientCallbacks.ReceiveMicrophoneData = [](void* context, unsigned char* data, int size)->bool {
      return reinterpret_cast<XRScene*>(context)->ReceiveMicrophoneData(data, size);
    };
  }

  MTXRError ret = MTXRCreateReceiver(&m_desc, &m_receiver);
  if (MTXRError_Success == ret) {
    if (fd > 0) {
      MTXRConnectUSB(m_receiver, fd);
    } else {
      MTXRConnect(m_receiver, serverIp.c_str());
    }
  }
}

4.3 主循环​

MTVerseXR客户端App的主循环中需要根据当前的状态做出不同的行为。

  • Receiver未创建:显示一些交互UI,比如服务器的IP地址,让用户可以选择不同的连接方式。

  • 未连接到服务器:显示加载提示,告知用户正在连接服务器。

  • 成功连接到服务器:开始接收服务器传输的音视频数据。

  • 有可用的视频帧:判断当前是否有可用的视频帧,根据结果显示最新的视频或者缓存的视频帧。

  • 连接断开:用户主动断开连接后,应用需要清理相关资源。

渲染服务器视频流步骤:

  1. 获取可用视频帧:调用MTXRFetchFrame获取当前可用视频数据。
void XRScene::BeginFrame(int64_t predictedDisplayTime, const MTXRVRTrackingState& pose, const std::vector<XrView>& xrViews, bool showPerfUI) {
  {
    std::lock_guard<std::mutex> guard(m_poseLock);
    m_xrState = pose;
  }

  ……
  m_xrFrame = std::make_shared<MTXRFramesFetched>();
  MTXRFetchFrame(m_receiver, m_xrFrame.get(), predictedDisplayTime, 0);
}

  1. 渲染视频帧:MTXRFetchFrame成功后,调用MTXRRenderFrame显示当前最新视频帧,否则跳过绘制或者显示之前的缓存。注意需要在激活GLES 3.2上下文环境的渲染线程中调用。
void XRScene::RenderFrame(const XrCompositionLayerProjectionView &layerView, int viewId) {
  MTXRPosef pose;
  pose.position = {layerView.pose.position.x, layerView.pose.position.y, layerView.pose.position.z};
  pose.orientation = {layerView.pose.orientation.x, layerView.pose.orientation.y, layerView.pose.orientation.z, layerView.pose.orientation.w};

  MTXRFovf fov = {layerView.fov.angleLeft, layerView.fov.angleRight, layerView.fov.angleUp, layerView.fov.angleDown};

  MTXRRenderFrame(m_receiver, m_xrFrame.get(), viewId == 0 ? MTXRFrameMask_Left : MTXRFrameMask_Right, &pose, &fov);
}

void RenderView(int viewID,
                XrTime predictedDisplayTime,
                std::shared_ptr<XRScene> xrScene,
                const XrCompositionLayerProjectionView &layerView,
                const XrSwapchainImageBaseHeader *swapchainImage,
                int64_t swapchainFormat) override {
  glBindFramebuffer(GL_FRAMEBUFFER, m_swapchainFramebuffer);

  const XrSwapchainImageOpenGLESKHR* swapchainImageGLES = reinterpret_cast<const XrSwapchainImageOpenGLESKHR *>(swapchainImage);
  const uint32_t colorTexture = swapchainImageGLES->image;

  glViewport(static_cast<GLint>(layerView.subImage.imageRect.offset.x),
             static_cast<GLint>(layerView.subImage.imageRect.offset.y),
             static_cast<GLsizei>(layerView.subImage.imageRect.extent.width),
             static_cast<GLsizei>(layerView.subImage.imageRect.extent.height));

  glFrontFace(GL_CW);
  glCullFace(GL_BACK);
  glDisable(GL_CULL_FACE);
  glEnable(GL_DEPTH_TEST);

  const uint32_t depthTexture = GetDepthTexture(colorTexture);

  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0);
  glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0);

  // Clear swapchain and depth buffer.
  glClearColor(BackgroundColor[0], BackgroundColor[1], BackgroundColor[2], BackgroundColor[3]);
  glClearDepthf(1.0f);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

  if (xrScene) {
    xrScene->RenderFrame(layerView, viewID);
  }
  glBindFramebuffer(GL_FRAMEBUFFER, 0);

  // Swap our window every other eye for RenderDoc
  static int everyOther = 0;
  if ((everyOther++ & 1) != 0) {
    ksGpuWindow_SwapBuffers(&window);
  }
}

  1. 释放视频帧:绘制完成后,需要调用MTXRReleaseFrame通知MTVerseXR SDK内部释放和回收视频资源。
void XRScene::EndFrame() {
  MTXRReleaseFrame(m_receiver, m_xrFrame.get());
  m_xrFrame = nullptr;
}

4.4 资源清理​

退出客户端应用前,需要调用MTXRDestroyReceiver释放MTVerseXR的相关资源。

note

相关安装包、源码可以通过开发者社区下载:MTVerseXR SDK | 摩尔线程开发者)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/888683.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

c++(多态)

多态的定义 多态是⼀个继承关系的下的类对象&#xff0c;去调⽤同⼀函数&#xff0c;产⽣了不同的⾏为 ⽐如Student继承了Person。Person对象买票全价&#xff0c;Student对象优惠买票。 多态实现的条件 • 必须指针或者引⽤调⽤虚函数 第⼀必须是基类的指针或引⽤&#xff0c;…

性能测试-JMeter(1)

性能测试工具 主流性能测试工具LoadrunnerJMeter JMeter环境安装JMeter功能概要JDK常用文件目录介绍JMeter元件和组件介绍元件的基本介绍组件的基本介绍 JMeter元件作用域和执行顺序JMeter第一个案例线程组HTTP请求查看结果树 JMeter参数化&#xff08;重点&#xff09;用户定义…

涛思数据库安装和卸载

安装 cd opt/taos/TDengine-server-2.4.0.5 sudo ./install.sh 启动taos​ 安装后&#xff0c;请使用 systemctl 命令来启动 TDengine 的服务进程 systemctl start taosd检查服务是否正常工作&#xff1a; systemctl status taosd 升级 3.0 版在之前版本的基础上&#x…

Vue3 集成 json-editor-vue3

简介 快速编辑json数据&#xff0c;还需要支持全屏编辑&#xff0c;以及json校验。 https://github.com/guyue88/json-editor-vue3 安装依赖 npm install json-editor-vue3 --save 引入 在 main.js中添加 import “jsoneditor”; 全局引入 import Vue from vue import Json…

无人自助超市系统小程序源码开发

随着科技的飞速发展和消费模式的转变&#xff0c;无人自助超市作为一种新兴的商业模式&#xff0c;以其便捷性、高效率以及对“体验式购物”的完美诠释&#xff0c;受到了广泛关注。本文renxb001将深入探讨无人自助超市系统小程序源码开发的核心环节和技术要点。 一、系统需求分…

Electron构建桌面应用程序,服务于项目的自主学习记录(持续更新...

无所畏惧地面对未知&#xff0c;并将其视为成长的机会 大纲官网快速入门1.安装node.js -- 这里推荐用nvm管理2.脚手架创建3.electron 包安装到应用的开发依赖4.创建主进程(main.js)并启动项目1.创建页面2.配置main.js3.启动项目 -- 效果 进阶 -- 基于项目场景功能使用场景一&am…

近年来自动驾驶行业就业与企业需求情况

自动驾驶行业在近年来持续发展&#xff0c;就业情况和企业需求呈现出多样化和复杂化的趋势。 以下是基于我搜索到的资料对自动驾驶行业最新就业情况和企业需求的详细分析&#xff1a; 自动驾驶行业对高端技术人才的需求非常旺盛&#xff0c;尤其是架构工程师、算法工程师等岗…

某乎登录加密以及zseck加密逆向

注意,本文只提供学习的思路,严禁违反法律以及破坏信息系统等行为,本文只提供思路 如有侵犯,请联系作者下架 某乎的登录除了需要通过网易易盾外,登录还需要传额外的加密data参数,某盾的加密可以看我之前的文章,这里着重讲解登录以及后续ck的加密,将最终的的登录采集代码…

通过MySQL Workbench 将 SQL Server 迁移到GreatSQL

通过MySQL Workbench 将 SQL Server 迁移到GreatSQL 一、概述 MySQL Workbench 提供了可以将Microsoft SQL Server的表结构和数据迁移到 GreatSQL 的功能&#xff0c;此次将通过MySQL Workbench将SQL Server的数据迁移到GreatSQL。 本文章只是简单演示一下单张表的迁移&…

【LeetCode】每日一题 2024_10_8 旅行终点站(哈希)

前言 每天和你一起刷 LeetCode 每日一题~ LeetCode 启动&#xff01; 国庆结束了 . . . 力扣的每日一题也来到了终点站 题目&#xff1a;旅行终点站 代码与解题思路 func destCity(paths [][]string) string { // 国庆结束&#xff0c;旅途到了终点// 今天这道题算是一个小…

【LeetCode: 1870. 准时到达的列车最小时速 | 二分】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

看门狗电路设计

看门狗电路设计 看门狗是什么应用架构图TPV6823芯片功能硬件时序图为什么要一般是要保持200个毫秒左右的这种低电平的时间看门狗电路实际应用与条件 看门狗是什么 硬件看门狗芯片&#xff0c;Watch DogTimer&#xff0c;可用于受到电气噪音、电源故障、静电放电等影响(造成软件…

“炫我”受邀出席虚拟现实及元宇宙产业创新论坛!

当前&#xff0c;新一轮科技革命和产业变革向纵深演进&#xff0c;虚拟现实及元宇宙等相关产业加速发展&#xff0c;催生了新产业新业态新模式&#xff0c;发展潜力巨大、应用前景广阔。 9月27日&#xff0c;由北京市科学技术委员会、中关村科技园区管理委员会&#xff0c;北京…

JavaScript 访问者模式:打造高扩展性的对象结构

一. 前言 在面向对象编程中&#xff0c;访问者模式&#xff08;Visitor Pattern&#xff09;是一种行为设计模式&#xff0c;它允许我们向现有的类结构添加新的操作&#xff0c;而无需修改这些类。这对于需要对类层次结构中的元素进行复杂算法处理的场景非常有用。 本文将详细…

【AI绘画SD教程】Lineart线稿上色和IP-Adapter 人像写真插件实操教学,轻松助你生成多种风格的AI人像大片!SD零基础入门到精通教程

大家好&#xff0c;我是画画的小强 今天给大家分享一下如何用AI绘画工具StableDiffusion当中的 LineArt线稿处理 和 IP-Adapter 实操教学。 本期教程开始之前&#xff0c;请先确保你的电脑已经安装好StableDiffusion这款AI绘图工具&#xff0c;如你还没有安装使用&#xff0c…

最新价值5000元的V2M2引擎传奇源码2024BLUE升级版 团购

最新团购的V2M2引擎源码2024年BLUE升级版 特点优势是最新XE12编辑器&#xff0c;微端&#xff0c;各种自定义UI 无限仿GOM引擎功能 参考地址&#xff1a;最新价值5000元的V2M2引擎传奇源码2024BLUE升级版[原始团购版]_1234FCOM专注游戏工具及源码例子分享下载地址:BlueCodePXL…

适合技术小白入门 AI 编程的六个场景

前言 AI 编程最近特别热闹。 自媒体文章说它很强大&#xff0c;确实身边也会看到技术小白用它做出酷炫作品&#xff0c;令人艳羡。 但你自己用时却常遇到坑&#xff0c;找技术朋友一问听到的回答是“AI 干不了这个、铁定会把你带沟里去”。 谁说得对&#xff1f;技术小白到底能…

Linux——磁盘分区、挂载

Linux 分区 原理介绍 原理图如下 当我们在/home目录下新建一个文件a.txt时&#xff0c;该文件实际上是存放在硬盘B的分区1中的&#xff0c;这就是图里说的&#xff0c;当进入某个目录&#xff0c;可以进入到该目录下挂载的分区里的意思 硬盘说明 应用实例&#xff1a;挂载一个…

Linux的六个入侵检查思路及预防

背景 入侵检查是保障计算机安全运行的重要手段之一&#xff0c; 通过操作系统的静态配置分析、日志分析、异常行为分析以及文件完整性等方式来做检查&#xff0c;来判断我们的操作系统是否有受到入侵。今天阿祥就介绍十个简单的入侵检查思路及应对措施&#xff0c;希望对大家有…

基于JavaWeb开发的java springmvc+mybatis学生考试系统设计和实现

基于JavaWeb开发的java springmvcmybatis学生考试系统设计和实现 &#x1f345; 作者主页 网顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; &#x1f345; 查看下方微信号获取联系方式 承接各…