Cesium集成WebXR_连接VR设备
Cesium集成WebXR
文章目录
- Cesium集成WebXR
- 1. 需求
- 2. 技术基础
- 2.1 WebGL
- 2.2 WebXR
- 2.3 其他
- 3. 示例代码
- 4. 效果图
- 5. 参考链接
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 = ssession.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 renderergl.bindFramebuffer(gl.FRAMEBUFFER, glLayer.framebuffer);// Clear the GL context in preparation to render the new framegl.clearColor(0, 0, 0, 1.0);gl.clearDepth(1.0); // Clear everythinggl.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. 效果图

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]. 旋转变换(一)旋转矩阵
相关文章:
Cesium集成WebXR_连接VR设备
Cesium集成WebXR 文章目录Cesium集成WebXR1. 需求2. 技术基础2.1 WebGL2.2 WebXR2.3 其他3. 示例代码4. 效果图5. 参考链接1. 需求 通过WebXR接口,将浏览器端连接到VR头盔,实现在VR头盔中浏览Cesium场景,并可将头盔旋转的操作同步映射为场景…...
物联网在物流行业中的应用
物流管理需要同时监控供应链、仓储、运输等多项活动,然而许多因素会影响物流流程本身并导致延迟。为了简化流程和提高客户满意度,一些行业领导者和决策者积极创新,不断评估并使用物联网对物流流程的成本效益进行深入优化。在本文中࿰…...
<c++> 类与对象 | 面向对象 | 访问说明符 | 类的声明 | 创建类
文章目录前言面向过程编程面向对象编程什么是类类和结构体有什么区别三个访问说明符如何创建一个类类的声明创建类申明和定义全部放在类中声明和定义分离前言 从这里我们正式开始学习c中的面向对象编程,在学习之前,我们有必要了解一下什么是面向对象编程…...
恭喜!龙蜥社区荣登 2022 科创中国“开源创新榜”
2 月 20 日,中国科协召开以“创新提振发展信心,科技激发产业活力”为主题的2023“科创中国”年度会议。会上,“科创中国”联合体理事长、中国工程院院士周济介绍了 2022 年系列榜单征集遴选情况,并与中国科协副主席、中国工程院院…...
2023双非计算机硕士应战秋招算法岗之机器学习基础知识
目录 特征工程 2 缺失值处理 15 评价指标 33 逻辑回归 37 决策树 40 随机森林 46 SVM 49 Knn 56 Kmeans 59 PCA 66 朴素贝叶斯 68 常见分类算法的优缺点 72 特征工程 1.什么是特征工程 有这么一句话在业界广泛流传,数据和特征决定了机器学习的上限,而模型…...
二、TS的基础类型、类型注解
TS的基础类型、类型注解 TS的基础类型 js的数据类型: 基础数据类型(7个) boolean string number null undefined BigInt Symbol 引用数据类型(1个) Object 变量后面多了一个注解,注解为变量限定数据类型&…...
3年经验,3轮技术面+1轮HR面,拿下字节30k*16薪offer,这些自动化测试面试题值得大家借鉴
面试一般分为技术面和hr面,形式的话很少有群面,少部分企业可能会有一个交叉面,不过总的来说,技术面基本就是考察你的专业技术水平的,hr面的话主要是看这个人的综合素质以及家庭情况符不符合公司要求,一般来…...
分类预测 | MATLAB实现WOA-CNN-LSTM鲸鱼算法优化卷积长短期记忆网络数据分类预测
分类预测 | MATLAB实现WOA-CNN-LSTM鲸鱼算法优化卷积长短期记忆网络数据分类预测 目录分类预测 | MATLAB实现WOA-CNN-LSTM鲸鱼算法优化卷积长短期记忆网络数据分类预测分类效果基本描述模型描述程序设计参考资料分类效果 基本描述 1.Matlab实现WOA-CNN-LSTM多特征分类预测&…...
自然语言处理(NLP)之近似训练法:负采样与层序Softmax
我们在前面介绍的跳字模型与连续词袋模型有个缺陷就是在计算梯度时的开销随着词典增大会变得很大,因为每一步的梯度计算都包含词典大小数目的项的累加。为了降低这种带来的计算复杂度,介绍两种近似的处理方案:负采样和层序softmax负采样(Nega…...
关于上位机,C#
TCP与modbusTCP的区别 (10条消息) C#高级--常用数据结构_李宥小哥的博客-CSDN博客_c# 数据结构 C#中常用的数据结构 TCP/IP协议是网络通讯协议。MODBUS是应用与工业现场(电子控制)的通讯协议。两者的应用范围和应用环境有…...
华为OD机试真题 用 C++ 实现 - 字符串加密 | 多看题,提高通过率
最近更新的博客 华为OD机试 - 入栈出栈(C++) | 附带编码思路 【2023】 华为OD机试 - 箱子之形摆放(C++) | 附带编码思路 【2023】 华为OD机试 - 简易内存池 2(C++) | 附带编码思路 【2023】 华为OD机试 - 第 N 个排列(C++) | 附带编码思路 【2023】 华为OD机试 - 考古…...
达梦8数据守护动态增加实时备库
实时主备环境 类型 业务IP 库名 实例名 PORT_NUM MAL_HOST MAL_INST_DW_PORT MAL_PORT MAL_DW_PORT 主库dm8p 192.168.1.223 DAMENG GRP1_RT_01 5236 10.0.0.223 45101 55101 65101 备库dm8s 192.168.1.224 DAMENG GRP1_RT_02 5236 10.0.0.224 45121…...
《代码整洁之道 - 程序员的职业素养》读书笔记
一 前言 《代码整洁之道 - 程序员的职业素养》的作者是Robert C. Martin,大家喜欢喊他Bob大叔。这本书主要是Bob大叔40年编程生涯的心得体会,主要讲述了一个专业的程序员需要具备什么样的态度,遵循什么样的原则,采取什么样的行动。…...
八、CSS新特性二
文章目录一、CSS3多背景和圆角二、怪异盒子模型三、多列属性四、H5多列布局瀑布流五、CSS3线性渐变5.1 线性渐变5.2 径向渐变六、CSS3过渡动画七、CSS3 2D八、CSS3动画一、CSS3多背景和圆角 css3多背景,表示CSS3中可以添加多个背景。 CSS3圆角 border-radius: 0px;…...
Ubuntu国内镜像源
查看系统版本命令: $ lsb_release -aDistributor ID: UbuntuDescription: Ubuntu 22.04 LTSRelease: 22.04Codename: jammy国内的更新源有多个,几个大互联网公司的源都比较稳定,没什么差别。 下面是比较主流的、常用的几个…...
3.Linux安装es单机版
1.下载 版本 JDK 11ES elasticsearch-7.10.0 jdk安装 下载: wget https://download.java.net/openjdk/jdk11/ri/openjdk-1128_linux-x64_bin.tar.gz配置环境变量:# 编辑配置文件 vim /etc/profile# Java11环境变量配置 export JAVA_HOME/devtools/ja…...
C语言实现通讯录
咱们手机上面还有教务系统上都可以存储信息,这些都是使用编程语言来实现的,那么今天,咱们今天就用C语言来实现通讯录。 一. 实验名称 通讯录 二. 实验目标 1.数据的储存 2.数据的增加 3.数据的删除 4.数据的修改 5.数据的展示 6.数据…...
Python-生成列表
1.生成列表使用列表前必须先生成列表。1.1使用运算符[ ]生成列表在运算符[ ]中以逗号隔开各个元素会生成包含这些元素的新列表。另外,如果[ ]中没有元素就会生成空列表示例>>> list01 [] >>> list01 [] >>> list02 [1, 2, 3] >>…...
如何写好controller层
前言本篇主要要介绍的就是controller层的处理,一个完整的后端请求由4部分组成:1. 接口地址(也就是URL地址)、2. 请求方式(一般就是get、set,当然还有put、delete)、3. 请求数据(request,有head跟body)、4. 响应数据(response)本篇…...
MySQL---视图的概念与操作
MySQL—视图的概念与操作 常见的数据库对象 对象描述表(TABLE)表是存储数据的逻辑单元,以行和列的形式存在,列就是字段,行就是记录数据字典就是系统表,存放数据库相关信息的表。系统表的数据通常由数据库系统维护, 程…...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...
适应性Java用于现代 API:REST、GraphQL 和事件驱动
在快速发展的软件开发领域,REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名,不断适应这些现代范式的需求。随着不断发展的生态系统,Java 在现代 API 方…...
高效的后台管理系统——可进行二次开发
随着互联网技术的迅猛发展,企业的数字化管理变得愈加重要。后台管理系统作为数据存储与业务管理的核心,成为了现代企业不可或缺的一部分。今天我们要介绍的是一款名为 若依后台管理框架 的系统,它不仅支持跨平台应用,还能提供丰富…...
js 设置3秒后执行
如何在JavaScript中延迟3秒执行操作 在JavaScript中,要设置一个操作在指定延迟后(例如3秒)执行,可以使用 setTimeout 函数。setTimeout 是JavaScript的核心计时器方法,它接受两个参数: 要执行的函数&…...
