自在线聊天和社交网络兴起以来,互联网上的多用户体验已经走过了漫长的道路。虚拟现实技术的进步使网络成为一个更加沉浸式和交互式的环境。尼尔·斯蒂芬森设想了一套共享的、持久性的、互联的 3D 虚拟空间,并将其称为 *元宇宙*;今天,我们正在用 HTML、JavaScript 和 A-Frame 构建它。
鉴于 HTML 的学习曲线平缓,A-Frame 是那些希望用几行 HTML 和 JavaScript 在网络上创建虚拟空间的人的完美选择。随着浏览器中 链接遍历 的实现,我们离在现实世界中无需通勤即可从一个体验传送到另一个体验又近了一步。然而,仍然缺少一个协作模型来促进元宇宙居民之间信息交换。WebRTC 在实现这种交换方面发挥着关键作用。
使用 WebRTC 进行点对点通信
WebRTC 是一个 Web API,存在于 大多数浏览器 中(包括截至今年 9 月的 Safari),它允许以点对点的方式交换信息,无需中介。使用 WebRTC,可以实现将体验集成到元宇宙所需的持久基础设施。
WebRTC 最大的复杂性来自 会话管理、对等发现和信令,所有这些都是识别浏览器之间连接所必需的。一旦建立了对等身份,该标准就可以提供用于共享媒体和数据的端到端通道。
sharedspace
组件
为了将 WebRTC 的强大功能带给 A-Frame 用户,我一直在开发 sharedspace
组件。该组件提供了一个协作模型,参与者可以在其中加入或离开命名空间,共享音频和状态,并向其他对等方发送可 JSON 序列化的对象。
该组件不直接处理 WebRTC API。相反,它使用 修改后的版本 的 webrtc-swarm
作为包装库。我选择它是因为它的简单性、占地面积、源代码的清晰度以及易用性。
您可以体验一些 VR 聊天在 Glitch 上 或 浏览项目 以了解有关 sharedspace
组件的更多信息。该存储库包含 丰富的文档,其中包含其他常见用例的解释和示例。sharedspace
组件不是 A-Frame 的通用网络解决方案,它没有提供一种直接方法来在应用程序的多个实例之间共享实体。但是,发送数据的能力意味着可以基于此组件创建新的协作形式。
对于更通用的网络组件,请查看 networked-aframe
组件,作者是 Hayden Lee。
兼容性
sharedspace
组件需要支持 WebRTC 的浏览器,这意味着 大多数流行的移动和桌面浏览器的任何最新版本。Chrome 还要求支持 WebRTC 的页面通过 HTTPS 提供服务,除非您从 localhost
提供服务。
它是如何工作的?
这是实现共享空间所需的最小 HTML 代码
<!-- Inside head -->
<script src="https://aframe.io/releases/0.7.0/aframe.min.js"></script>
<script src="https://cdn.rawgit.com/delapuente/aframe-sharedspace-component/master/dist/aframe-sharedspace-component.min.js"></script>
<script src="https://rawgit.com/feiss/aframe-environment-component/master/dist/aframe-environment-component.min.js"></script>
<!-- Inside body -->
<a-scene>
<a-entity sharedspace avatars>
<!-- Actually, this is not needed but convenient to have some reference points -->
<a-entity environment="preset: forest"><a-entity>
</a-entity>
</a-scene>
<template>
<a-sphere radius="0.1" color=”#ff0000”></a-sphere>
</template>
但是,上面的代码将始终连接到名为 room-101
的房间,并且化身表示将是红色的球体,这对人类参与者来说不是有效的表示。让我们自定义设置来更改它。
您可以按照我的步骤自定义代码,使用相同的 最小设置 在 Glitch 上:重制项目。
重要事项:要测试您的进度,您至少需要两个客户端连接到同一个房间。在测试时,您会注意到对等方已连接,因为相机已重置,并且应用程序不再允许您移动化身。当发生这种情况时,寻找一个红色的球:这是另一个对等方。
随机生成的房间名称
sharedspace
组件将在 A-Frame 场景准备就绪后立即尝试连接到房间。一旦组件已连接,更改其属性将不起作用。要阻止组件连接服务器,请将 hold
属性设置为 true
<a-entity sharedspace="hold: true" avatars></a-entity>
准备一个脚本,以便场景加载完成后修改它。在 body
的结束标记之前添加以下 script
标记
<script>
var scene = document.querySelector('a-scene');
(function start() {
if (!scene.hasLoaded) {
scene.addEventListener('loaded', start);
return;
}
// Now it’s safe to change the scene components...
}());
</script>
用以下 JavaScript 替换注释,该 JavaScript 将检查当前 URL 以查找要连接到的房间。如果未找到房间,应用程序将生成一个新房间并替换地址栏中的 URL,以允许用户邀请他们的朋友加入该房间
var prefix = window.location.host.split('.')[0] + '-';
var currentUrl = new URL(window.location);
var roomName = currentUrl.search.substr(1);
if (!roomName) {
roomName = prefix + Date.now();
currentUrl.search = roomName;
history.pushState({}, '', currentUrl.href);
}
var room = document.querySelector('[sharedspace]');
room.setAttribute('sharedspace', { room: roomName, hold: false });
最重要的部分是最后一行,您在其中设置房间的名称并将 hold
属性重置为 false
,允许组件连接。
自定义化身
安装 sharedspace
组件后,avatars
组件可用。它管理 A-Frame 场景,为每个参与者提供化身表示。默认情况下,avatars
组件将搜索 template
标记并使用其内容来实例化化身。
用以下基本体替换 template
标记的内容
<template>
<a-entity>
<a-sphere radius="0.1" color="#ffffff"></a-sphere>
<a-sphere position="0.05 0.03 -0.08" radius="0.02" segments-width="8" segments-height="8" color="#000000"></a-sphere>
<a-sphere position="-0.05 0.03 -0.08" radius="0.02" segments-width="8" segments-height="8" color="#000000"></a-sphere>
<a-sphere class="themable" position="0 -0.07 -0.1" scale="1 1 0.5" segments-width="4" segments-height="4" radius="0.02" color="#11fd3e"></a-sphere>
<a-cone class="themable" position="0.03 -0.07 -0.1" rotation="0 0 90" scale="1 1 0.5" segments-radial="8" segments-height="1" height="0.03" radius-bottom="0.03" color="#1cff3c"></a-cone>
<a-cone class="themable" position="-0.03 -0.07 -0.1" rotation="0 0 -90" scale="1 1 0.5" segments-radial="8" segments-height="1" height="0.03" radius-bottom="0.03" color="#1cff3c"></a-cone>
</a-entity>
</template>
修复方向
不知道连接时相机指向的方向可能会很烦人。让我们解决这个问题。当参与者加入房间时,avatars
组件将实例化化身模板并在其实体上发出 avataradded
事件。这允许动态配置模板。
找到您获取房间元素的行,并在该行中添加以下代码(在将 hold
设置为 false
之前)
room.addEventListener('avataradded', function onAdded(evt) {
var avatar = evt.detail.avatar;
if (!avatar.hasLoaded) {
avatar.addEventListener('loaded', onAdded.bind(null, evt));
return;
}
var avatarY = avatar.getAttribute('position').y;
avatar.object3D.lookAt(new THREE.Vector3(0, avatarY, 0));
var radToDeg = THREE.Math.radToDeg;
var rotation = avatar.object3D.rotation;
rotation.y += Math.PI;
avatar.setAttribute('rotation', {
x: radToDeg(rotation.x),
y: radToDeg(rotation.y),
z: radToDeg(rotation.z)
});
});
请注意,avataradded
不能保证化身实体已加载。您应该等待化身完全加载,然后才能安全地更改其他组件。该代码使用底层 Three.js API 来计算化身的正确方向。
位置音频
使用 WebRTC 流式传输音频非常普遍,以至于 sharedspace
组件与 avatars
组件协作,使它变得非常简单。只需将 audio
属性设置为 true
<a-entity sharedspace="hold: true; audio: true" avatars>
下次您加载体验时,浏览器将要求您允许共享您的麦克风。
如果参与者授予权限,A-Frame 化身的位置音频将由 avatars
组件自动管理。位置音频意味着声音将根据监听器(即相机)的相对位置进行左右声场处理。佩戴耳机或耳塞可以增强这种效果。
共享位置
您可能已经注意到,表示用户的化身有特殊处理。因为它的化身“携带”相机,所以当您环顾四周时,您的方向将由其他参与者共享。默认情况下,avatars
将向用户的化身添加一些特定的组件。
您可以使用 A-Frame 混合器 控制应该向用户的化身应用哪些组件。混合器是组件容器,实体可以将 mixin
属性设置为混合器 ID 列表以 *继承* 其组件。
在带有混合器内部的 a-scene
标记之后添加一个 a-assets
标记,并将它的 id
设置为 users
<a-assets>
<a-mixin id="user" visible="false" look-controls wasd-controls share="position, rotation"></a-mixin>
</a-assets>
share
组件(在注册 sharedspace
后也可用)指示哪些组件应该在其他对等方之间保持同步。
通过将 sharedspace
的 onmyself
属性设置为混合器的 id
,您是在指示 avatars
向用户的化身添加该混合器。
<a-entity sharedspace="hold: true; audio: true" avatars="onmyself: user">
发送和接收消息
sharedspace
组件允许用户向其他对等方发送消息。您将使用此功能在按下空格键时强制对预设环境进行更改。
找到您向 avataradded
事件添加监听器的位置,并插入以下代码来管理环境预设
var presets = [
'contact', 'egypt', 'checkerboard', 'forest',
'goaland', 'yavapai', 'goldmine', 'threetowers',
'poison', 'arches', 'tron', 'japan',
'dream', 'volcano', 'starry', 'osiris'
];
var environment = document.querySelector('[environment]');
function setEnvironment(preset) {
environment.setAttribute('environment', { preset: preset });
}
function getNextPreset() {
var currentPreset = environment.getAttribute('environment').preset;
var index = presets.indexOf(currentPreset);
return presets[(index + 1) % presets.length];
}
// Here comes the code to send and receive message….
最后,用以下代码替换注释,用于接收和发送消息
window.addEventListener('keydown', function (evt) {
if (evt.keyCode === 32 /* spacebar */) {
var preset = getNextPreset();
setEnvironment(preset);
room.components.sharedspace.send('*', { type: 'environment', preset: preset });
}
});
room.addEventListener('participantmessage', function (evt) {
if (evt.detail.message.type === 'environment') {
var preset = evt.detail.message.preset;
setEnvironment(preset);
}
});
下一步是什么?
本文展示了如何将最小的共享空间设置演变为引人入胜的多用户户外体验。但这仅仅是开始。如果您想继续改进演示,以下是一些您可以尝试的操作
- 获取并 共享参与者的姓名。
- 更改参与者出现的顺序,通过实验
placement
属性来进行。 - 尝试在 参与者消息 的基础上实现共享房间状态。
组件存储库 包含 对组件 API 的详细说明 和 Glitch 上的模板 VR 聊天项目,包括 源代码指南,可以帮助您快速熟悉这些组件。
寻找更多创意?在 Unbirthday Room 中,这里还有另一个由 sharedspace
支持的多用户应用程序。
结论
多用户应用程序不仅限于聊天:其他参与性体验也适合 sharedspace
模型。即使提出的参与模型有限,其他组件也可以在此基础上构建,以实现新的交互。
现在轮到您构建多用户体验了:安装 A-Frame 和 sharespace
,进行黑客攻击,录制演示,并在 Twitter 上提及 @aframevr 来告知我们。加入活跃的 Slack 频道,并告诉我们您的协作体验。
关于 Salva
Mozilla 的前端开发人员。开放网络和 WebVR 倡导者,我喜欢编程语言、电影、音乐、电子游戏和啤酒。
3 条评论