Cesium集成WebXR_连接VR设备

这篇具有很好参考价值的文章主要介绍了Cesium集成WebXR_连接VR设备。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Cesium集成WebXR

1. 需求

通过WebXR接口,将浏览器端连接到VR头盔,实现在VR头盔中浏览Cesium场景,并可将头盔旋转的操作同步映射为场景视角的变换,实现沉浸式体验。

2. 技术基础

2.1 WebGL

需要了解一些关于WebGL的基础知识,通过以下几个链接可快速了解:

  • WebGL 入门
  • WebGL 着色器获取js数据
  • 【零基础学WebGL】绘制矩形
  • 【零基础学WebGL】绘制图片

2.2 WebXR

关于WebXR可参见MDN上有关介绍Fundamentals of WebXR。

WebXR, with the WebXR Device API at its core, provides the functionality needed to bring both augmented and virtual reality (AR and VR) to the web.

WebXR is an API for web content and apps to use to interface with mixed reality hardware such as VR headsets and glasses with integrated augmented reality features. This includes both managing the process of rendering the views needed to simulate the 3D experience and the ability to sense the movement of the headset (or other motion-sensing gear) and provide the needed data to update the imagery shown to the user.

另外,MDN提供了一个例子可以帮助快速上手,该示例未依赖其他三维框架(如three.js),使用纯原生WebGL接口,相关介绍见Movement, orientation, and motion: A WebXR example,在线运行示例见WebXR: Example with rotating object and user movement(可浏览源代码,并下载到本地运行调试)。

2.3 其他

另外需要了解一些矩阵变换(平移、缩放、旋转)知识,可参考以下链接:

  • Matrix math for the web - MDN
  • 旋转变换(一)旋转矩阵

3. 示例代码

注:未接入实体VR设备,使用浏览器插件 WebXR API Emulator 模拟。

<!DOCTYPE html>
<html lang="en">

<head>
  <!-- Use correct character set. -->
  <meta charset="utf-8" />
  <!-- Tell IE to use the latest, best version. -->
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <!-- Make the application on mobile take up the full browser screen and disable user scaling. -->
  <meta name="viewport"
    content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
  <title>Hello World!</title>
  <script src="../Build/Cesium/Cesium.js"></script>
  <style>
    @import url(../Build/Cesium/Widgets/widgets.css);

    html,
    body,
    #cesiumContainer {
      width: 100%;
      height: 100%;
      margin: 0;
      padding: 0;
      overflow: hidden;
    }

    .cesium-viewer-vrContainer {
      z-index: 10000;
    }
  </style>
</head>

<body>
  <div id="cesiumContainer"></div>
  <script>
    // Cesium.Ion.defaultAccessToken = 'your_token';
    var viewer = new Cesium.Viewer("cesiumContainer", {
      vrButton: true
    });

    let gl, refSpace, xrSession, animationFrameRequestID;
    let originalDirection; // 进入VR模式前的场景相机信息

    // vrButton设置监听事件,进入vr模式后检测vr设备
    viewer.vrButton.viewModel.command.afterExecute.addEventListener(() => {
      // 刚进入VR模式
      if (viewer.vrButton.viewModel.isVRMode) {
        setTimeout(() => {
          // 检查当前环境
          if (navigator.xr) {
            // 检查是否支持 immersive-vr 模式
            navigator.xr.isSessionSupported('immersive-vr').then((supported) => {
              if (supported) {
                // 请求VR会话
                navigator.xr.requestSession('immersive-vr').then(sessionStarted);
                originalDirection = viewer.camera.direction;
              } else {
                console.error("未检测到VR设备");
              }
            }).catch(() => {
              console.error("检测失败");
            });
          } else {
            console.error("当前浏览器不支持 WebXR");
          }
        }, 200);
      } else {
        // 刚退出VR模式
        if (xrSession) xrSession.end();
      }
    });

    /**
     * VR会话开始
     * @param {*} session 
     */
    function sessionStarted(session) {
      xrSession = session;

      // 监听会话结束事件
      xrSession.addEventListener("end", sessionEnded);

      // 与普通 WebGL 不同,这里需要设置 xrCompatible 参数
      gl = viewer.scene.canvas.getContext('webgl', { xrCompatible: true });
      // gl.makeXRCompatible();

      // 更新会话的渲染层,后续渲染会渲染在该层上
      session.updateRenderState({ baseLayer: new XRWebGLLayer(session, gl) });

      // 请求 local 空间,跟踪用户头部旋转
      session.requestReferenceSpace('local').then(s => {
        refSpace = s
        session.requestAnimationFrame(onXRFrame); // 开始渲染
      })
    }

    /**
     * VR会话结束
     */
    function sessionEnded() {
      // If we have a pending animation request, cancel it; this
      // will stop processing the animation of the scene.

      if (animationFrameRequestID) {
        xrSession.cancelAnimationFrame(animationFrameRequestID);
        animationFrameRequestID = 0;
      }
      xrSession = null;
    }

    let lastTransMatrix = [
      1, 0, 0, 0,
      0, 1, 0, 0,
      0, 0, 1, 0,
      0, 0, 0, 1];
    /**
     * 设备渲染帧
     * @param {*} time 
     * @param {*} frame 
     */
    function onXRFrame(time, frame) {
      const session = frame.session;

      animationFrameRequestID = session.requestAnimationFrame(onXRFrame);

      // viewer.scene.render()

      const pose = frame.getViewerPose(refSpace)
      // 获取旋转和视图信息
      if (pose) {
        let glLayer = frame.session.renderState.baseLayer;

        // Bind the WebGL layer's framebuffer to the renderer
        gl.bindFramebuffer(gl.FRAMEBUFFER, glLayer.framebuffer);

        // Clear the GL context in preparation to render the new frame
        gl.clearColor(0, 0, 0, 1.0);
        gl.clearDepth(1.0);                 // Clear everything
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

        pose.views.forEach(view => {
          let viewport = glLayer.getViewport(view);
          gl.viewport(viewport.x, viewport.y, viewport.width, viewport.height);
          gl.canvas.width = viewport.width * pose.views.length;
          gl.canvas.height = viewport.height;

          // 视角映射
          if (view.eye == 'left') {
            // let matrix = Cesium.Matrix4.fromRowMajorArray(view.transform.inverse.matrix, new Cesium.Matrix4());
            // let result = Cesium.Matrix4.multiplyByPoint(matrix, originalDirection, new Cesium.Cartesian3());


            // 矩阵应该使用上次变换的矩阵,而不是从刚进入VR模式后整个过程中的总矩阵
            let mergedTransMatrix = Cesium.Matrix4.fromRowMajorArray(view.transform.inverse.matrix, new Cesium.Matrix4());
            let realTransMatrix = Cesium.Matrix4.multiply(Cesium.Matrix4.fromRowMajorArray(lastTransMatrix, new Cesium.Matrix4()),
              mergedTransMatrix, new Cesium.Matrix4());
            let result = Cesium.Matrix4.multiplyByPoint(realTransMatrix, viewer.camera.direction, new Cesium.Cartesian3());
            viewer.camera.direction = result;
            viewer.scene.render();
            lastTransMatrix = view.transform.matrix; // 矩阵的逆,作为下次计算基础
          }
        })
      }
    }

    // XXX: 
    // 1. 【view.transform.inverse.matrix】矩阵中既包括了头盔旋转变换,也包含了位置平移变换(针对有距离传感器的VR设备),
    // 最终将整个矩阵应用到了Cesium场景的【camera.direction】,逻辑是不合理的,【camera.direction】应该只对应头盔旋转变换。
    // The transform property describes the position and orientation of the eye or camera represented by the XRView, 
    // given in that reference space.
    // 2. 根据[WebXR基础介绍](https://developer.mozilla.org/en-US/docs/Web/API/WebXR_Device_API/Fundamentals#field_of_view),
    // 左右两只眼看到的应该是有细微差别的。在官方示例中[如https://webxr-experiment.glitch.me/]可以看出,都是将一个canvas分成了
    // 左右两块区域,然后根据XRView中的左右眼信息分别在两块区域绘制,但是Cesium未暴露出类似【gl.drawElements】的接口,只有
    // 【scene.render】,调用后只会在整个canvas区域上进行绘制,没有左右分区的效果,所以借助了Cesium自带的VRButton,在进入Cesium
    // 的VrMode后,再调用WebXR接口连接设备,同时XRView也只处理左眼,利用Cesium自身的左右同步。隐患未知。

  </script>
</body>

</html>

4. 效果图

cesium vr,Cesium,WebXR,Cesium,VR

5. 参考链接

[1]. WebXR 技术调研 - 在浏览器中构建扩展现实(XR)应用
[2]. 【WebAR】虚拟现实来到网页——WebXR Device API第二部分
[3]. Fundamentals of WebXR
[4]. WebXR: Example with rotating object and user movement
[5]. WebGL 入门
[6]. 【零基础学WebGL】绘制矩形
[7]. Matrix math for the web - MDN
[8]. 旋转变换(一)旋转矩阵文章来源地址https://www.toymoban.com/news/detail-791449.html

到了这里,关于Cesium集成WebXR_连接VR设备的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity XR 设置VR设备手柄按键按下事件

    ①打开XRI Default Input Action 面板。 ②设置左手柄上的按键就点击Action Maps 列表下的 XRI LeftHand Interaction选项,设置右手柄上的按键就点击XRI RightHand Interaction。 ③以设置右手柄上的按键为例,我们将设置右手柄上的 A键、B键、摇杆按下键、摇杆上下左右推动事件、R2键(扳机键

    2024年01月19日
    浏览(47)
  • 微信小程序集成three.js--VR全景项目源码

    小程序集成Three.js,展示不同贴图材质的运用 实现VR全景效果的部分,主要实现步骤如下: 1 创建一个正方体 2加载6个不同面的图片作为正方体的材质 3设置正方体属性 cube.geometry.scale(1,1,-1),即完成了正方体面的反转 4将camera的位置设置在正方体内部,即实现了从内部观察正

    2024年02月11日
    浏览(50)
  • 任天堂开发全新独立VR设备,或为下一代主机?将提供混合现实体验

    根据爆料人Nash Weedle在X平台上的发文,我们得知任天堂正在秘密开发一款全新的独立VR设备,该设备将拥有一块MicroLED屏幕,并且独立于任天堂传闻中的下一代主机。与此同时,谷歌也参与了这款VR产品的研发工作。 这一新的VR设备被设计成适合家庭多人使用,它将提供混合现

    2024年02月09日
    浏览(42)
  • 使用U3D、pico开发VR(一)——将unity的场景在设备中呈现

           最近srtp项目在赶进度,自己之前是在电脑端进行的开发。但是项目是VR端,因此需要重新学习,在此记录一下自己的学习经历。        首先,如何将unity的场景在自己的眼镜中进行呈现呢?        对此,我也找了很多教程,也跟着花了很多时间去做。从国内的

    2024年01月17日
    浏览(64)
  • VR智能家居虚拟连接仿真培训系统重塑传统家居行业

    家居行业基于对场景的打造及设计,拥有广阔前景,是众多行业里面成为最有可能进行元宇宙落地的应用场景之一。 家居行业十分注重场景的打造及设计,而元宇宙恰恰能通过将人工智能、虚拟现实、大数据、物联网等技术融合提升,带来身临其境的感官体验。简单来讲,就

    2024年02月07日
    浏览(50)
  • Unity基于PICO4设备实现VR下的多场景切换(巨详细,案例全csdn仅此一家)

    打开unity Hub,先点击左侧项目一栏,再点击右上角的新项目,弹出创建窗口后,选择URP模板,自定义项目名称和位置,取消勾选版本管理,最后点击创建项目即可(注意:我这里的unity版本为2020.3.37f1c1 LTS)。 点击创建项目后,第一次创建项目时,需等待一段时间加载,项目初

    2024年02月10日
    浏览(65)
  • 士兰微六轴陀螺仪SC7I22在AR/VR头显设备中的应用

         士兰微是一家集成电路和半导体制造商。它专注于研发和生产高性能的MEMS传感器,如加速度计、陀螺仪和组合传感器。这些高精度设备广泛应用于消费电子、汽车、工业以及AR/VR等领域。通过技术创新,士兰微旨在提供可靠的传感器解决方案,以促进智能设备的发展。

    2024年02月21日
    浏览(46)
  • 106.(cesium篇)cesium椎体旋转

    地图之家总目录(订阅之前建议先查看该博客) 下面献上完整代码,代码重要位置会做相应解释

    2024年02月03日
    浏览(52)
  • 108.(cesium篇)cesium初始定位动画

    地图之家总目录(订阅之前建议先查看该博客) 下面献上完整代码,代码重要位置会做相应解释

    2024年02月05日
    浏览(63)
  • 105.(cesium篇)cesium指南针

    地图之家总目录(订阅之前建议先查看该博客) 文章末尾处提供保证可运行完整代码包,运行如有问题,可“私信”博主。 效果如下所示: 下面献上完整代码,代码重要位置会做相应解释

    2024年02月03日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包