雨果·巴拉:行业北极星Vision Pro过度设计不适合产品市场

Meta发布Mixed Reality Motif新工具包:简化多人MR体验开发流程

查看引用/信息源请点击:映维网Nweon

简化多用户设置

映维网Nweon 2025年05月16日)Mixed Reality Motif是一个帮助你在混合现实体验中快速执行常见机制的蓝图。为了帮助开发者克服在混合现实中构建高质量、同步的多人游戏体验所带来的挑战,Meta日前分享了Mixed Reality Motif的新系列:简化多用户设置。

多用户社交体验正在兴起。对于Meta Horizon Store而言,一项重要的功能是Colocation,它指的是当用户距离非常接近(通常在10米以内)时,自动检测并接入Meta Quest设备的游戏和应用。

通过使用诸如基于蓝牙的Colocation Discovery和Shared Spatial Anchor等技术,开发者可以将虚拟内容与物理世界同步,并确保用户能够与共享物理空间中的相同数字对象进行交互。

从Shared Spatial Anchors的基本知识和通过网络共享它们到使用Colocation Discovery立即设置托管体验,团队将在这个Motif中引导你完成支持Colocation的关键步骤。

为了扩展你的Colocation 用例,你可以访问GitHub的Motif项目,查找有关如何设置Space Sharing AP的步骤指南。你同时可以查看这个YouTube视频教程,或参阅下方的文字介绍。

1. Spatial Anchor基础

Spatial Anchor是一个世界锁定的参考框架,它为物理世界中的虚拟对象提供位置和方向。应用程序可以为每个虚拟对象使用一个Spatial Anchor,或者选择多个虚拟对象使用同一个Spatial Anchor,只要对象在其三米的覆盖范围内即可。

Anchor API提供了数个关键特性:

  • 跨会话的持久性:锚的姿态可以持久化。

  • 跨会话发现:可以发现和重用锚。

  • 与其他用户共享:锚可以同步或异步共享。

GitHub项目提供了SpatialAnchorManager, SpatialAnchorStorage和SpatialAnchorLoader类来帮助管理锚,介绍了如何使用Anchor API来实现创建、保存、加载和删除锚等基本操作。

1.1 创建锚

你可以通过实例化一个包含OVRSpatialAnchor组件的prefab来创建一个锚,或者在场景中使用一个现有的对象并添加OVRSpatialAnchor组件。这将分配一个UUID并异步创建锚。

// C/C++
var anchor = gameObject.AddComponent();

while (!anchor.Created)
{
await Task.Yield();
}

锚包含一个名为“Created”的属性,用于检查创建是否已经成功完成。作为最佳实践参考,建议等待创建锚完成。

1.2 保存锚

可以通过调用OVRSpatialAnchor.SaveAnchorAsync来保存锚。

// C/C++
await anchor.SaveAnchorAsync();
SpatialAnchorStorage.SaveUuidToPlayerPrefs(anchor.Uuid);

ColocatedExperiences项目包含一个静态的SpatialAnchorStorage类,它允许你将锚保存到Unity PlayerPrefs中。你可以调用示例的SaveUuidToPlayerPrefs函数来在设备存储空间锚。

这个函数用一个计数将新的UUID添加到PlayerPrefs中。这样,你就可以轻松地跟踪多个UUID并在以后访问它们。

// C/C++
public static void SaveUuidToPlayerPrefs(Guid uuid)
{
var count = PlayerPrefs.GetInt(NumUuidsKey, 0);
PlayerPrefs.SetString($"{UuidKeyPrefix}{count}", uuid.ToString());
PlayerPrefs.SetInt(NumUuidsKey, count + 1);
PlayerPrefs.Save();
}

1.3 加载锚

加载锚可以通过SpatialAnchorLoader类实现,它包括三个独立的步骤:加载、定位和绑定。

当加载时,锚最初未绑定,这意味着锚尚未接到预期的GameObject的OVRSpatialAnchor组件。锚必须绑定以管理其生命周期,并提供对其他功能(如保存和擦除)的访问。

要加载锚,你需要它的UUID。由于UUID存储在PlayerPrefs中,你可以从静态SpatialAnchorStorage类查询UUID列表。

// C/C++
var uuids = SpatialAnchorStorage.LoadAllUuidsFromPlayerPrefs();

接下来,你可以调用LoadUnboundAnchorsAsync函数。在这个步骤中,最佳实践是在调用LocalizeAsync对锚进行定位之前等待成功的结果。当你定位一个锚时,它会致使系统确定锚点在世界中的姿势。


// C/C++
var unboundAnchors = new List();
await OVRSpatialAnchor.LoadUnboundAnchorsAsync(uuids, unboundAnchors);

foreach (var unboundAnchor in unboundAnchors)
{
    if (await unboundAnchor.LocalizeAsync())
  {
  // Bind anchor here
  }
}              

定位成功后,你可以通过调用内置的BindTo函数将未绑定的锚绑定到它的OVRSpatialAnchor组件。

// C/C++
if (!unboundAnchor.TryGetPose(out var pose))
{
return;
}

var anchorObject = Instantiate(anchorPrefab.gameObject, pose.position, pose.rotation);
var spatialAnchor = anchorObject.GetComponent();

unboundAnchor.BindTo(spatialAnchor);           

1.4 擦除锚

OVRSpatialAnchor.EraseAnchorAsync函数用于从持久存储中擦除空间锚。在那之后,最好的做法是擦除锚GameObject,停止在运行时跟踪它,从而为新的锚释放存储空间。

// C/C++
await anchor.EraseAnchorAsync();
Destroy(anchor.gameObject);


使用上述步骤,你现在可以轻松地创建、保存、加载和删除锚。接下来,我们将介绍共享锚和对齐用户的姿势的关键配置功能。

2. 创造共在体验

为了设置Colocation,你可以在Unity Meta XR SDK的v71及以上版本中使用Colocation Discovery。这个功能允许附近的用户通过蓝牙发现彼此,并且它属于OVRColocationSession类。通常,广告客户端寻求充当多用户体验的主机,而发现客户端对加入托管体验感兴趣。

2.1 Colocation Discovery的需求

要启用Colocation Discovery,需要将OVR Manager的Colocation Session Support权限设置为“Required”,从而将以下权限添加到Android Manifest文件中:


// C/C++



Colocation的要求非常少,但需要满足以下三个条件之一:

  • 用户是经过验证的开发者组织的成员。

  • 用户是来自拥有应用程序的开发者组织的测试用户。

  • 用户由开发者组织通过Release Channel邀请(Production除外)。

对于共享空间锚,共享空间锚支持权限同样需要设置为“Required”。另外,设备必须接到互联网。最后,Meta Quest设备必须启用增强空间服务。打开“增强空间服务”,进入“设置>隐私和安全>设备权限”,选择“增强空间服务”。应用程序将检测设置何时禁用,并通知用户打开它。

2.2 理解基于组的锚共享和加载

从v71开始,空间锚共享和加载变成基于组,而不是基于用户。这消除了用户对应用的授权需求,以及开发者通过在Developer Dashboard验证应用来管理用户ID的需求。你可以使用任意组UUID来共享和加载锚,所以推荐使用Group Sharing。

在与组共享空间锚之前,其中一个参与者(通常是主机)必须创建一个表示组的UUID,并将其传递给其他参与者。这种通信可以通过应用管理的网络来实现,比如Unity Netcode或Photon Fusion,或者通过Colocation Discovery来实现,从而大大减少最终用户在设置Colocation体验方面的摩擦。

2.3 Colocation Discovery:会话广告和锚共享

组ID是自动生成。在下面的代码中,主机开始发布,成功发布后,你可以从发布结果中读取组ID。

// C/C++
var advertisementResult = await OVRColocationSession.StartAdvertisementAsync(null);
_groupId = advertisementResult.Value;

// Create and save anchor here



除了在StartAdvertisementAsync函数中发送null之外,你同时可以以字符串的形式发送一定的会话信息,例如会话名称,或者简单地作为消息发送给其他用户。最多可以发送1024字节的数据。

在使用上面介绍的步骤创建并保存空间锚之后,你可以调用基于组的函数来共享锚。


// C/C++
OVRSpatialAnchor.ShareAsync(new List { anchor }, _groupId);


2.4 Colocation Discovery:会话发现和锚加载

在主机开始发布会话并成功共享锚(包括创建的组ID)之后,所有其他用户都可以发现会话。下面你可以看到,在使用StartDiscoveryAsync开始发现之前,已订阅了OnColocationSessionDiscovered事件。

// C/C++
OVRColocationSession.ColocationSessionDiscovered += OnColocationSessionDiscovered;
OVRColocationSession.StartDiscoveryAsync();

一旦发现了Colocation会话,就会激活OnColocationSessionDiscovered。接下来,你可以从发现的会话中读取组ID,并使用它来加载锚。

// C/C++
private void OnColocationSessionDiscovered(OVRColocationSession.Data sessionData)
{
_groupId = session.AdvertisementUuid;
// Load anchor here
}


如前所述,现在可以加载锚,但这次函数名为LoadUnboundSharedAnchorsAsync,并将你的组ID作为输入。

// C/C++
var unboundAnchors = new List();
await OVRSpatialAnchor.LoadUnboundSharedAnchorsAsync(_groupId, unboundAnchors);

成功加载锚之后,请记住按照上面介绍的步骤定位并绑定到OVRSpatialAnchor组件。

2.5 锚对齐

现在,用户已经准备好与锚的姿势对齐。对齐是创建真正共在体验的关键步骤,因为它确保所有用户与主机拥有相同的追踪空间。为了实现这一点,你可以调整用户的Camera Rig位置并旋转到锚的姿势。

// C/C++
cameraRig.Transform.position = anchor.Transform.InverseTransformPoint(Vector3.zero);
cameraRig.Transform.eulerAngles = new Vector3(0, -anchor.Transform.eulerAngles.y, 0);

3. 使用Space Sharing API

现在,你可以使用Meta XR SDK v74及以上版本的Space Sharing API来更进一步。

在MRUK中托管的Space Sharing API确保房间布局能够在客户端之间无缝共享,同时为流行的Colocation用例提供无缝解决方案。

3.1 需求和限制

只有主机需要事先或在体验开始时扫描房间。

APK必须上传到Developer Dashboard的Release Channel,所有用户或测试用户必须获邀或成为组织的一份子。

不可能在两个具有相同帐户的设备之间共享空间。所以,在开发过程中测试空间共享的方法有两种:

  • 使用你的设备和别人的设备,并在两者之间共享一个空间。确保其他设备的帐户有权使用你的应用程序。

  • 创建一个测试用户,并在第二台设备使用测试用户登录。对于这种情况,确保测试用户的电子邮件受邀到Release Channel,并有权使用应用。

3.2 空间共享设置

为了简化设置过程,你可以将Space Sharing API 与 Colocation Discover结合起来。要共享一个房间,主机需要与MRUK单例实例通信,获取MRUK房间列表并调用内置的ShareRoomsAsync函数。

// C/C++
// For sharing multiple rooms
var rooms = MRUK.Instance.Rooms;
MRUK.Instance.ShareRoomsAsync(rooms, _groupId);

// For sharing a single (current) room
var room = MRUK.Instance.GetCurrentRoom();
room.ShareRoomAsync(_groupId);

类似地,其他用户可以加载与组ID共享的所有房间,并将自己与房间的地板世界姿势对齐。

// C/C++
MRUK.Instance.LoadSceneFromSharedRooms(null, _groupId, alignmentData: (roomUuid, remoteFloorWorldPose));

有关如何获取所有房间信息(如地板世界姿势)的详细代码和信息,请访问这个

本文链接https://news.nweon.com/129760
转载须知:转载摘编需注明来源映维网并保留本文链接
素材版权:除额外说明,文章所用图片、视频均来自文章关联个人、企业实体等提供
QQ交流群苹果Vision  |  Meta Quest  |  微软HoloLens  |  AR/VR开发者  |  映维粉丝读者

您可能还喜欢...

资讯