当前位置: 首页 > news >正文

Three.js WebXR沉浸式渲染简明教程

在前面文章中,我们了解了 VR 概念以及它们如何在 WebXR 中映射。 这使你可以考虑想要为用户提供的体验。 在本文中,我们将介绍如何将 WebXR 与 Three.JS 结合使用来创建针对大型异构用户群的沉浸式体验。

警告:WebXR API 仍在完善中(第一个公共工作草案刚刚发布),因此我将尽力更新本系列以反映更改并保持这些文章常青。 WebXR 设备 API 规范将出现新功能,如果它简化了代码,我将相应地更新本文。

在这里插入图片描述

用 3DConvert 在线工具快速转换3D模型的格式,无需本地安装。

1、Three.js 渲染管线快速概览

我不会花太多时间讨论 Three.JS 渲染管道的工作原理,因为它在互联网上有详细记录(例如此处)。 我将在下图中列出基础知识,以便更容易理解各个部分的去向。

在这里插入图片描述

2、WEBXR 设备 API 入门

在我们深入了解 WebXR API 本身之前,您应该知道 WebXR 设备 API Polyfill 可通过两种主要方式帮助开发人员:

如果设备/浏览器不支持 WebXR 设备 API,它将尝试使用陀螺仪和加速计等可用传感器对其进行填充,从而允许开发人员提供基本的纸板式体验或内联渲染。

如果浏览器支持旧版 WebVR API,它将在 WebVR 之上填充 WebXR 设备 API,从而允许开发人员首先利用为支持 WebVR 所做的所有工作(从而允许其利用其下方的 VR 运行时)。

用户可以进入的主要 3D 体验类型包括:

  • 基于台式计算机的键盘/鼠标,没有任何沉浸式支持。
  • 利用手机传感器的内联渲染或魔术窗口。 内联渲染是一种很好的方式来“逗弄”用户你的内容,向他们展示你的体验,希望这能让他们单击按钮并在 HMD 内进入更身临其境的体验。 这是一个例子:

在这里插入图片描述

  • 具有专用 VR 系统的沉浸式 VR、基于移动设备的 VR 或类似纸板的体验。

WebXR 设备 API 基于会话的概念。 例如,你请求会话,浏览器负责在 HMD 中启动渲染。 当你结束会话时,渲染会在 HMD 内停止,你可以像往常一样在页面上再次开始渲染。 会话有 3 种类型:沉浸式 VR、沉浸式 AR(本文未介绍)和内联。

这是一个非常简单的流程图,可以帮助你根据设备功能或 WebXR 设备 API 支持等因素决定提供哪种体验。

在这里插入图片描述

3、请求WebXR会话并呈现内容

本节介绍使用 WebXR 设备 API 请求会话和呈现内容所需步骤的高级流程。 我们将在某些步骤中详细介绍,主要关注渐进方面而不是渲染本身。

在本文中,我们将参考此处的一个简单演示。 它使用 WebXR 和 Three.JS,是本文中代码片段的基础。 完整来源位于此处。

4、检查 WEBXR 支持

你会发现不支持 WebXR 设备 API(即使使用 WebXR polyfill)的浏览器或设备并不罕见。 在这种情况下,你可以考虑基于键盘和鼠标的回退,而不是提供空页面,以便用户可以在体验中导航(类似于 3D 游戏)。

在 Three.JS 中,支持这一点相对简单。 你可以使用 PointerLockControls 类自动映射鼠标来移动相机(与 FPS 射击游戏的方式相同)。 使用指针锁定的好处是,当获取锁定时,它将发送鼠标移动的增量而不是它们在视口中的绝对位置。 另一个好处是,除非用户解锁指针(通常使用转义键,为您提供暂停体验的方法),否则光标无法离开浏览器窗口,并且光标将被隐藏。 这非常适合我们的需要。

this._controls = new THREE.PointerLockControls(this._camera);
this._scene.add(this._controls.getObject());

请注意,THREE.PointerLockControls 不会为你锁定指针。 通常,你希望与一个按钮进行交互来开始,该按钮会提醒用户将要发生某些事情。 这是执行此操作的一段简化代码:

document.body.addEventListener( 'click', _ => {// Ask the browser to lock the pointerdocument.body.requestPointerLock = document.body.requestPointerLock ||document.body.mozRequestPointerLock ||document.body.webkitRequestPointerLock;document.body.requestPointerLock();
}, false);
THREE.PointerLockControls 将在鼠标移动时负责更新相机。

最后要处理的部分是键盘移动,这非常简单:

document.addEventListener('keydown', event => {this._onKeyDown(event)}, false);
document.addEventListener('keyup', event => {this._onKeyUp(event)}, false);

在你的处理程序中,只需更新存储在某个变量中的相机的位置即可。 在演示中,我存储了预期的运动方向,因为我通过速度来平滑运动,这样用户看起来就不会跳跃位置。

完成更新渲染函数内的位置后,请更新 THREE.PointerLockControls:

let controls_yaw = this._controls.getObject();
controls_yaw.translateX(new_position.x);
controls_yaw.translateZ(new_position.z);

然后照常渲染场景并使用 requestAnimationFrame 再次循环:

this._renderer.render(this._scene, this._camera);
return requestAnimationFrame(this._update);

5、检查支持的WebXR会话模式

如果你的浏览器支持 WebXR(无论是本机还是通过 polyfill),需要查询 XR 会话支持的模式来决定后续步骤,例如,添加一个按钮以进入沉浸式模式。 下面是一个尝试确定是否支持沉浸式 VR 模式的示例:

navigator.xr.supportsSession('immersive-vr').then(() => {this._createPresentationButton();
}).catch((err) => {console.log("Immersive VR is not supported: " + err);
});

如果Promise得到解析,那么你可以在页面中添加一个按钮,通知用户他们可以使用他们拥有的 HMD 进入 VR 模式。 你还可以使用内联会话进行查询,看看是否可以在页面内渲染某些内联内容(也称为魔术窗口)。

6、调整以添加对 WEBXR 设备 API 的支持

如果将 Three.JS 渲染循环设置为在 2D 屏幕上进行常规渲染,则需要对其进行调整以支持使用 WebXR 进行渲染。 首先,以下是渲染如何与 WebXR 设备 API 一起工作的基本流程,无论是沉浸式会话还是内联会话。

在这里插入图片描述

让我扩展一下该图中的一些方框:

请求会话

navigator.xr.requestSession({mode: 'request-mode'})

mode参数可以是 immersive-vr、 immersive-ar 或 inline。 请记住,如果在你询问支持和请求会话之间 XR 设备不再可用,请妥善处理拒绝。

请求参考空间

当 requestSession Promise成功解决后,可以使用以下方式请求参考空间:

xrSession.requestReferenceSpace({ type:'type' })

本文前面讨论了各种可能的类型和子类型。 如果要指定子类型,请使用以下代码:

xrSession.requestReferenceSpace({ type:'type', subtype:'subtype' })

我建议你请求体验所需的功能最少的参考空间,因为它允许你支持更广泛的现有 XR 设备。

7、设置 XR 层

我不会在这里深入讨论细节,因为这里的 WebXR 设备 API 解释器对此进行了详细介绍。 然而,我将介绍正在进行内联渲染的具体示例,然后用户想要“升级”他们的体验以切换到更沉浸的模式。

现在,如果你想要使用内联模式然后切换到沉浸式模式,则需要两个画布:一个用于渲染沉浸式内容,另一个用于渲染内联内容。 每个画布都有自己的 webgl 上下文。 需要两个上下文的主要原因是,当你要求 GL 上下文与 XR 兼容(使用 makeXRCompatible)时,底层实现确保在连接 HMD 的 GPU 上创建上下文。 这与具有多个 GPU 的计算机非常相关,其中 HMD 可能连接到包含附加 GPU 的外壳。

注意:WebXR 设备 API 社区内部进行了一次讨论,以避免可能需要 2 个会话,从而更轻松地从一种体验切换到另一种体验。 这是正在讨论的问题。 还有一项工作正在进行中,以避免必须请求 2 个会话(一个内联,一个沉浸式),这将简化相当多的代码。

以下是使用 Three.JS 设置 XR 层的代码:

await this._renderer.context.makeXRCompatible();
this._xrSession.baseLayer = new XRWebGLLayer(this._xrSession, this._renderer.context);

8、调整渲染以支持沉浸式 VR 渲染

每当你使用 WebXR 设备 API 进行渲染时,渲染循环都需要更新。 首先也是最重要的,你不会在窗口上请求新的动画帧,而是在会话本身上请求新的动画帧。 原因是 XRSession 将根据 HMD 建议的刷新率以正确的频率调用你的代码。

在VR中,刷新率很可能与主屏幕的刷新率不同。 例如,一些一体式 HMD 的刷新率为 72 Hz,而 Oculus* Rift 或 HTC* Vive 等高端 VR HMD 的刷新率为 90 Hz,我们预计会看到 120 Hz 的 HMD 在不久的将来刷新率。 以更高刷新率渲染 VR 体验的主要原因之一是为用户提供流畅、更舒适的体验(这也有助于对抗晕动病)。

通常你会有这样的东西:

this._xrSession.requestAnimationFrame(this._render);

渲染函数如下所示:

function _render(timestamp, xrFrame);

xrFrame参数是携带当前XR设备渲染当前帧所需信息的对象。 在继续渲染之前,需要对 Three.JS 进行一些记录,以确保渲染可以与 WebXR 配合使用:

// Disable autoupdating because these values will be coming from the
// xrFrame data directly.
this._scene.matrixAutoUpdate = false;// Make sure not to clear the renderer automatically, because we will need
// to render it ourselves twice, once for each eye.
this._renderer.autoClear = false;// Clear the canvas manually.
this._renderer.clear();

下一步是最终进入 WebXR 特定的渲染位。 首先,你需要绑定层,这意味着你将告诉 Three.JS 渲染器渲染到 XRSession 层:

let xrLayer = this._xrSession.baseLayer;
this._renderer.setSize(xrLayer.framebufferWidth, xrLayer.framebufferHeight, false);
this._renderer.context.bindFramebuffer(this._renderer.context.FRAMEBUFFER, xrLayer.framebuffer);

然后你需要获取设备的姿态(姿态是旋转和位置,如果有的话):

let pose = xrFrame.getViewerPose(xrReferenceSpace);
if (!pose)return;

该姿态将为你提供渲染 XR 设备场景所需的所有信息。 然后你将需要渲染视图。 WebXR 设备 API 具有视图概念,通常映射到 VR HMD 内的屏幕数量。 通常,你将有 2 个视图(每只眼睛一个):

在这里插入图片描述

从那里你可以迭代视图并渲染每只眼睛:

for (let view of pose.views) {let viewport = xrSession.baseLayer.getViewport(view);this._renderEye(pose.viewMatrix, view.projectionMatrix, viewport);
}

渲染每只眼睛将如下所示:

_renderEye(viewMatrixArray, projectionMatrix, viewport) {// Set the left or right eye half.this._renderer.setViewport(viewport.x, viewport.y, viewport.width, viewport.height);let viewMatrix = new THREE.Matrix4();viewMatrix.fromArray(viewMatrixArray);// Update the scene and camera matrices.this._camera.projectionMatrix.fromArray(projectionMatrix);this._camera.matrixWorldInverse.copy(viewMatrix);this._scene.matrix.copy(viewMatrix);// Tell the scene to update (otherwise it will ignore the change of matrix).this._scene.updateMatrixWorld(true);this._renderer.render(this._scene, this._camera);// Ensure that left eye calcs aren't going to interfere.this._renderer.clearDepth();
}

“视图”方法的最佳部分是,你可以继续为内联会话重用相同的渲染代码,因为唯一的区别(除了矩阵值之外)是你只有一个要渲染的视图。


原文链接:Three.js WebXR渲染入门 — BimAnt

相关文章:

Three.js WebXR沉浸式渲染简明教程

在前面文章中,我们了解了 VR 概念以及它们如何在 WebXR 中映射。 这使你可以考虑想要为用户提供的体验。 在本文中,我们将介绍如何将 WebXR 与 Three.JS 结合使用来创建针对大型异构用户群的沉浸式体验。 警告:WebXR API 仍在完善中&#xf…...

flask使用cookie (设置cookie与查看cookie内容)

1.flask包cookie的使用 设置cookie app.route(/set_cookie) def set_cookie():resp make_response(Setting cookie)resp.set_cookie(username, John)return resp查看cookie: app.route(/get_cookie) def get_cookie():username request.cookies.get(username)return Welco…...

信息学奥赛一本通——1281:最长上升子序列

文章目录 题目【题目描述】【输入】【输出】【输入样例】【输出样例】 AC代码 题目 【题目描述】 一个数的序列 b i b_i bi​&#xff0c;当 b 1 < b 2 < . . . < b S b_1<b_2<...<b_S b1​<b2​<...<bS​的时候&#xff0c;我们称这个序列是上升…...

vue3+antv x6自定义节点样式

先大致定下节点样式&#xff0c;需要展示标题&#xff0c;输入/输出连接桩&#xff0c; 参考样子大概是 https://x6.antv.antgroup.com/examples/showcase/practices#class 这是根据antv x6配置 非自定义节点 图表案例 结果 数据格式大概是 nodes:[{title:鸟,id:node1,ports…...

Arcgis中直接通过sde更新sqlserver空间数据库失败

问题 背景 不知道有没有人经历过这样一个情况,我们直接在Arcgis中通过sde更新serserver数据库会失败,就是虽然在sde更新sqlserver数据库,但是在Navicat中通过sql语句来查询,发现数据并没有更新,如:上图中,更新数据库后,第一张图是sde打开的sqlserver数据库,它的数据库…...

使用gewe框架进行微信群组管理(一)

友情链接&#xff1a;geweapi.com 点击访问即可。 管理员操作 小提示&#xff1a; 添加、删除、转让多个wxid时仅限于添加/删除管理员&#xff0c;1添加 2删除 3转让 请求URL&#xff1a; http://域名地址/api/group/admin 请求方式&#xff1a; POST 请求头&#xff1a…...

【Linux】UDP协议——传输层

目录 传输层 再谈端口号 端口号范围划分 认识知名端口号 两个问题 netstat与iostat pidof UDP协议 UDP协议格式 UDP协议的特点 面向数据报 UDP的缓冲区 UDP使用注意事项 基于UDP的应用层协议 传输层 在学习HTTP等应用层协议时&#xff0c;为了便于理解&#xff…...

【Linux进阶之路】进程(上)

文章目录 前言一、操作系统加载过程二、进程1.基本概念2.基本信息①运行并观察进程②创建子进程③僵尸与孤儿进程&#xff08;父子进程衍生出来的问题&#xff09;1. 僵尸进程&#xff08;Zombie状态&#xff09;2. 孤儿进程 3.基本状态①操作系统的状态&#xff08;统一&#…...

爬虫018_urllib库_cookie反爬_post请求百度翻译获取百分翻译内容_以及详细翻译内容---python工作笔记037

然后我们来看如何用urllib发送post请求,这里我们 用百度翻译为例 我们翻译一个spider,然后我们看请求,可以看到有很多 找到sug这个 可以看到这里的form data,就是post请求体中的内容 然后我们点击preview其实就是 返回的实际内容 然后请求方式用的post 然后我们把上面的信息…...

【Nginx】Nginx网站服务

国外主流还是使用apache&#xff1b;国内现在主流是nginx&#xff08;并发能力强&#xff0c;相对稳定&#xff09; nginx&#xff1a;高新能、轻量级的web服务软件 特点&#xff1a; 1.稳定性高&#xff08;没apache稳&#xff09;&#xff1b; 2.系统资源消耗比较低&#xf…...

go语言从0基础到安全项目开发实战

一.环境搭建并helloworld 搭建环境比较简单 1.1安装SDK 到以下链接下 Go下载 - Go语言中文网 - Golang中文社区 下载windows版本64位zip包 https://studygolang.com/dl/golang/go1.20.7.windows-amd64.zip 1.2配置环境变量 不配置的话就只能在bin目录下才能运行go命令 …...

Kubernetes Service 工作原理

本文介绍了 Kubernetes Service 的概念、原理和具体使用。 作者&#xff1a;沈亚军 爱可生研发团队成员&#xff0c;负责公司 DMP 产品的后端开发&#xff0c;爱好太广&#xff0c;三天三夜都说不完&#xff0c;低调低调… 本文来源&#xff1a;原创投稿 爱可生开源社区出品&am…...

面部表情识别4:C++实现表情识别(含源码,可实时检测)

面部表情识别4&#xff1a;C实现表情识别(含源码&#xff0c;可实时检测) 目录 面部表情识别4&#xff1a;C实现表情识别(含源码&#xff0c;可实时检测) 1.面部表情识别方法 2.人脸检测方法 3.面部表情识别模型(Python) &#xff08;1&#xff09; 面部表情识别模型的训练…...

提升Element UI分页查询用户体验与交互:实现修改未保存提示

我实现的功能是在 element ui 的分页组件中进行分页查询时&#xff0c;如果当前有未保存的修改数据就提示用户&#xff0c;用户可以选择是否放弃未保存的数据。确认放弃就重新查询数据&#xff1b;选择不放弃&#xff0c;不重新查询&#xff0c;并且显示条数选择框保持原样&…...

UML-时序图

目录 时序图 时序图构成: 对象: 消息: 生命线(激活): 活动条: 时序图举例: 时序图 时序图也叫顺序图、序列图. 时序图描述按照时间的先后顺序对象之间的动作过程&#xff0c;是由生命线和消息组成 时序图构成: 对象: 对象是类的实例&#xff0c;对象是通过类来创建的&…...

Seata - 入门笔记

1、事务 访问并可能更新数据库中数据库中各种数据线的一个程序执行单元 原子性&#xff1a;事务是一个不可分割的工作单位&#xff0c;一个事务要么都做要么都不做 一致性&#xff1a;必须是使数据库从一个一致性到另一个一致性的状态&#xff0c;中间状态不能被观察到 隔离…...

springboot使用aop排除某些方法,更新从另外一张表,从另外一张表批量插入

AOP 在Spring Boot中使用AOP时&#xff0c;如果想要排除某些方法不被切面所影响&#xff0c;可以通过使用切面表达式中的!within关键字来实现。以下是一个示例&#xff1a; Aspect Component public class MyAspect {Before("execution(* com.example.service.*.*(..)) …...

Go 语言面试题(二):实现原理

文章目录 Q1 init() 函数是什么时候执行的&#xff1f;Q2 Go 语言的局部变量分配在栈上还是堆上&#xff1f;Q3 2 个 interface 可以比较吗&#xff1f;Q4 两个 nil 可能不相等吗&#xff1f;Q5 简述 Go 语言GC(垃圾回收)的工作原理Q6 函数返回局部变量的指针是否安全&#xff…...

SAP MM学习笔记16-在库品目评价

在库品目评价是指评估物料。具体比如物料价格&#xff0c;数量&#xff0c;保管场所等发生变化的时候&#xff0c;判断是否发生了变化&#xff0c;要不要生成 FI票&#xff0c;用哪个FI科目来进行管理等内容就叫在库品目评价。 在库品目评价有很多层级&#xff0c;这里先讲3兄弟…...

Azure通过自动化账户实现对资源变更

Azure通过自动化账户实现对资源变更 创建一个自动化账户第一种方式 添加凭据&#xff08;有更改资源权限的账户&#xff0c;没有auth认证情况&#xff09;创建一个Runbook&#xff0c;测试修改 AnalysisServices 定价层设置定时任务&#xff1a;开始定时任务&#xff1a; 第二种…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

#Uniapp篇:chrome调试unapp适配

chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器&#xff1a;Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...

基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解

JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用&#xff0c;结合SQLite数据库实现联系人管理功能&#xff0c;并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能&#xff0c;同时可以最小化到系统…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…...

Python Ovito统计金刚石结构数量

大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

通过 Ansible 在 Windows 2022 上安装 IIS Web 服务器

拓扑结构 这是一个用于通过 Ansible 部署 IIS Web 服务器的实验室拓扑。 前提条件&#xff1a; 在被管理的节点上安装WinRm 准备一张自签名的证书 开放防火墙入站tcp 5985 5986端口 准备自签名证书 PS C:\Users\azureuser> $cert New-SelfSignedCertificate -DnsName &…...