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

news2024/11/28 16:38:29

在前面文章中,我们了解了 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 pointer
  document.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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++学习笔记总结练习:数值方法

数值方法 1.1 随机数 头文件 #include<random>随机数概述 随机数分布。随机数的分布方式distribution 随机数引擎。产生随机数engin。随机性的源头 随机数生成器。由一个随机数引擎和一个随机数分布&#xff0c;组合成一个随机数生成器。 随机数引擎的操作 编译器…

关于@JSONField的使用

1.此注解来自jar包com.alibaba.fastjson 今天分享一个有意思的事情。这个注解作用与类的属性上&#xff0c;如下&#xff1a; ApiModelProperty(value"开始时间,格式:yyyy-MM-dd",required true) JSONField(name"start_date",ordinal 1) private String…

扫盲!PRINCE2认证6大常见问题集锦!

一&#xff0c;什么是PRINCE2认证&#xff1f; PRINCE2是PRoject IN Controlled Environment&#xff08;受控环境下的项目管理&#xff09;的简称&#xff0c;也叫国际项目管理师认证&#xff0c;是英国商务部(OGC)在1996年开始推广世界三大项目管理体系之一。 PRINCE2是一套…

API数据安全风险飙升! 3场景1实践看美创科技API-SMAC有效防护

在某次实战攻防演练中&#xff0c;防守方层层布防&#xff0c;搭建了十分健全的防御体系&#xff0c;本以为万无一失&#xff0c;结果靶标悄无声息被拿下。事后溯源中才发现&#xff0c;一个存在未授权访问的历史API&#xff0c;成为了突破口&#xff0c;敏感信息被红队获取&am…

【LeetCode 75】第二十一题(1207)独一无二的出现次数

目录 题目: 示例: 分析: 代码运行结果: 题目: 示例: 分析: 用两个unordered_map来分别存放每个数字的出现次数和出现的次数这个数,有点绕,比如说有给的数组有两个1,那么第一个map存放的是(1,2),表示1这个数子出现了两次,而第二个map存放的是(2,true),表示有出现次数为2的数…

python——案例11:数值交换

案例11&#xff1a;数值交换xinput(输入一个数值赋值给x&#xff1a;) yinput(输入一个数值赋值给y&#xff1a;)tempx #创建临时变量&#xff0c;以此变量为基础进行逐次交换 xy ytemp print(交换后的X的值是:{}.format(x)) # print(交换后的Y的值是:{}.format(y)) #

java【native关键字】

描述&#xff1a; native只能修饰方法&#xff0c;表示这个方法的方法体代码不是用java语言实现的&#xff0c;而是由c/c语言编写的。但是对于java程序员来说&#xff0c;可以当作java的方法一样正常去调用它&#xff0c;或者子类重写它 语法&#xff1a; 用在方法的返回值类…

Chrome开发者工具探秘:元素面板的神奇魔法与实战解析

作为一名网络爬虫大师&#xff0c;我深知Chrome开发者工具中的元素面板是探索和理解网页结构的重要工具。在本文中&#xff0c;我将详细介绍元素面板的各项功能与使用方法&#xff0c;并通过实际案例&#xff0c;带您领略这个神奇魔法的威力。 元素面板&#xff1a;解读网页的…

本地跑Mapreduce程序的相关配置

本地跑MapReduce程序需要配置的代码 为了在本地运行MapReduce程序&#xff0c;需要加如下的东西 在项目中创建一个如图所示的包&#xff1a;org.apache.hadoop.io.nativeio&#xff0c;并在该包下面创建一个名为&#xff1a;NativeIO的类&#xff08;注意&#xff1a;名字不能…

AD19 基础应用技巧(PCB设置快捷键)

众所周知&#xff0c;学会一个软件的快捷键操作可以大大提高我们的工作效率。 那么&#xff0c;Altium Designer软件如何设置快捷键&#xff1f; 以设置走线/放置过孔为例。 菜单栏 - 【放置】- 然后【Ctrl 鼠标左键 单击过孔】进入【Edit Command】界面。 在快捷方式一栏…

247 个经典实用有趣的 Python 实例附源码

今天给大家整理了 247 个经典实用有趣的 Python 实例&#xff0c;185 页代码齐全可复制 pdf&#xff0c;几乎涵盖了 Python 各个方面的知识点&#xff0c;即可以帮助小白快速全面的学习 Python&#xff0c;也可以让老手通过实战练习来查缺补漏。 福利&#xff1a;文末有chat-g…

用于农业格局分析的新型大型航空影像数据库

第一次农业革命发生在大约12&#xff0c;000年前&#xff0c;当时人类定居并开始种植农作物。从那以后&#xff0c;我们极大地改善了农业的艺术和科学&#xff0c;扩大了规模和产量&#xff0c;并在此过程中塑造了人类文明。一场新的、人工智能驱动的农业革命现在开始了吗&…

《合成孔径雷达成像算法与实现》Figure3.4

代码对补零信号与未补零信号都进行了实现&#xff0c;补零信号更加贴近书中图3.4的样子&#xff1a; clc clear all close all%参数设置 TBP 100; %时间带宽积 T 10e-6; %脉冲持续时间 alpha_os [1.4,1.2,1.0,0…

报考红帽认证难不,红帽认证考试容易吗?

红帽认证是由红帽Linux公司推出的&#xff0c;红帽培训和测试非常注重培养实际的动手实战能力&#xff0c;主要包括RHCSA认证、RHCE认证和RHCA认证&#xff0c;每个等级的认证都是层层递进的。 要想参加RHCA认证就必须通过RHCE认证&#xff0c;且认证证书在有效期内方可参加。 …

【C++进阶之路】异常篇

文章目录 前言一、异常1.简单使用2.注意事项3.异常体系①C标准异常体系②自定义异常体系 4.总结优点缺点 前言 是否知道C语言独特的错误处理方式——返回错误码&#xff0c;我们可以根据错误码来识别错误信息&#xff0c;比如识别了错误码&#xff0c;我们再用strerror函数把错…

信号产生梳状滤波效应的原理和代码演示

声学的梳妆滤波效应&#xff0c;是由于信号沿不同路径传播&#xff0c;时延不同造成的&#xff0c;对吧&#xff1f; 是的&#xff0c;声学的梳妆滤波效应是由于声音信号在传播过程中经历多条不同路径的反射和折射&#xff0c;导致信号到达听者耳朵的时间延迟不同&#xff0c;从…

CentOS7 安装 MongoDB5

MongoDB是一种NoSQL数据库&#xff0c;它存储数据的方式与传统的关系型数据库不同。MongoDB使用文档数据库模型&#xff0c;将数据存储在自包含的、可扩展的BSON文档中。MongoDB具有高可用性、自动分片、动态查询能力、灵活性等优点&#xff0c;适合于许多不同的应用场景。 下…

springboot项目打包 以及打包碰到各种问题

PS:以上资料都来自于网络 1.IDEA 将springboot项目打包 IDEA如何打包springboot成jar包&#xff0c;并运行、停止、重启&#xff0c;本地依赖不能打包怎么办_真是6的不行的博客-CSDN博客 2.[WARNING] Error injecting: org.springframework.boot.maven.RepackageMojo 1.注释…

数学建模—分类模型

本讲将介绍分类模型。对于而分类模型&#xff0c;我们将介绍逻辑回归&#xff08;logistic regression&#xff09;和Fisher线性判别分析两种分类算法&#xff1b;对于多分类模型&#xff0c;我们将简单介绍Spss中的多分类线性判别分析和多分类逻辑回归的操作步骤下。 本题按水…

Appium PO模式UI自动化测试框架——设计与实践

&#x1f60f;作者简介&#xff1a;博主是一位测试管理者&#xff0c;同时也是一名对外企业兼职讲师。 &#x1f4e1;主页地址&#xff1a;【Austin_zhai】 &#x1f646;目的与景愿&#xff1a;旨在于能帮助更多的测试行业人员提升软硬技能&#xff0c;分享行业相关最新信息。…