50cb4072961dd94a49ff444ae394b99d
38-构建多人 AR 游戏

ARKit系列文章目录

2019年WWDC的《 Session 610 - Building Collaborative AR Experiences
主要内容速览:

  • 多人协作会话(Collaborative Session)
  • 多用户 AR 的 ARAnchor 最佳实践
  • SwiftStrike : 一个新的多人 AR 游戏

多人协作会话(Collaborative Session)

在介绍这个之前,先来回顾一下去年 ARKit 2 中推出的世界地图保存和加载。去年的 ARKit 2 需要一个主用户扫瞄建立世界地图,然后自己通过代码经过网络分享给其他用户。在此之后不管是主用户 User1 还是其他用户 User2 ,所有人新扫瞄到的特征点,新建立的世界地图部分,都只能在自己本地使用,无法共享出去。

而今年的 Collaborative Session 就是为了解决这些问题。它可以自动建立网络连接,自动管理其他用户的加入,自动共享新特征点,新地图扩展。

  • 实时多用户 AR 体验
  • 持续共享 ARAnchors 和地图数据
  • 无需区分主用户与其他用户

比如下面的 Demo,一开始左边和右边的两个不同用户,看到了不同场景,各自添加虚拟物体后,也只能看到自己添加的物体。 互相移动后,看到对方的场景, Collaborative Session 会自动同步世界地图和锚点信息,以及别人添加的 3D 虚拟物体。

这样两个用户的世界地图就合并成了同一个,两个用户也处于同一个网络中,后续再进行任何添加操作,对方也能自动看到。

这其中的原理,如下图所示:一开始,两个用户建立了各自的世界坐标和世界地图,并通过网络进行了交流,没有发现共同之处。当一个用户扫瞄到另一个用户扫瞄过的地方时,世界地图的内容就自动进行了合并。但是,每个用户自己地图的坐标原点仍然在原处,没有改变,只是增加了地图范围和其他用户的锚点信息,并持续更新

在 ARKit 3 中,想要用上 Collaborative Session ,首先,你必须让这些设备处于同一个网络层中(MultipeerConnectivity 或者其他网络技术)。然后你需要启用自己的 Collaboration,并传输相关数据到其他用户那里


在 ARKit 3中,只需要下面的代码就可以了。

// Collaborative Session
 // Create world tracking configuration
 let config = ARWorldTrackingConfiguration()
 // Enable collaborative session
 config.isCollaborationEnabled = true
 // Run the configuration
  session.run(config)

如果你用的不是 RealityKit,那还需要实现另外两个方法:

// ARSession delegate function to output ARCollaborationData
func session(_ session: ARSession, 

didOutputCollaborationData data: ARSession.CollaborationData) {
 // Transmit Data representation of the data to all other participants using MPC
 do {
 try self.mpcSession.send(data.data, toPeers: self.peerIds, with: .reliable)
 } catch {
 // Re-transmit the data if failed
 }
}


// MPC delegate function when receiving collaboration data from other users
func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
 // Pass the received data to ARSession
 self.arSession.update(data: ARSession.CollaborationData(data: data))
}

Collaborative Session 中的 ARAnchor

ARAnchor 具有:

  • 同步的生命周期:当你添加或删除锚点时,其他用户也会同步添加或删除
  • 带有会话标识(Session identifier):用来区分是谁创建了锚点
  • ARAnchor 的子类不会被共享:只共享用户创建的锚点,不包括 ARImageAnchor 等,也不包括用户自己实现的子类,比如用来携带某些数据等

那么在代码中,如何使用 ARAnchor?我们需要区分是谁在操作锚点:

// ARAnchor in collaborative session
// ARSession delegate function when an ARAnchor is added.
func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {
 for anchor in anchors {
  // Use session identifier to determine creator of the ARAnchor
  if anchor.sessionIdentifier == session.identifier {
   // Self-placed ARanchor
  } else {
   // ARAnchor from another participant
  }
 }
}

// ARSession delegate function when an ARAnchor is removed.
func session(_ session: ARSession, didRemove anchors: [ARAnchor]) {
 for anchor in anchors {
  // Use session identifier to determine creator of the ARAnchor
  if anchor.sessionIdentifier == session.identifier {
   // Self-placed ARanchor
  } else {
   // ARAnchor from another participant
  }
 }
}

ARParticipantAnchor

为了解决在多人 AR 中,如何显示其他用户的问题,我们今年引入了ARParticipantAnchor类型:

  • 代表其他用户的位置
  • 以高帧率更新
  • 在本地化其他用户的地图后,才会创建(这意味着,我们可以用它来确定多人共享是否已经开始了)

关于本地化其他用户,我们有一些建议

多人共享 AR 能够开启的前提,是大家看到了同一块区域。并且,如果你想要加快识别速度,最好是让多人处于相近的视角中。

还有就是,保持地图追踪状态ARFrame.WorldMappingStatus.mapped。它会让追踪到的 3D 地图数据不断更新,范围更大,准确度也更高。以便后面的其他用户匹配到同一个区域。

多用户 AR 的 ARAnchor 最佳实践

首先我们需要先了解一下 ARWorldMap:

  • 包含了压缩后的 3D 地形(Landmark)
  • 包含了相机姿态(特征点和地形被观察到时的相机姿态)

地形数据是根据相机姿态,分成不同组的,如下图 View 0,View 1,View 2 等

同时还要注意的是,ARAnchor 的绝对位置是依赖于世界坐标系的,即相对图中 World 原点的。同时这个位置又是相对世界地图的,即相对于整个地形中特征点的相对位置。

了解了这些原理后,我们就可以采取措施,优化 ARAnchor 的使用:

  • 实现 anchor 更新的代理方法:这样随着相机的移动,地形特征点也会发生校准移动,Anchor 的位置也会随着离它最近的 View 里面的地形数据而调整
  • 将 3D 内容放置靠近在 ARAnchor 的地方:如果离得太远,当 Anchor 随着地形数据更新时,3D 内容的位置会发生很大的移动
  • 对于每个独立的 3D内容,使用独立的不同的锚点:除非几个 3D 物体本身离得不远,且需要保持严格的相对距离,这样才能共用一个锚点
top Created with Sketch.