使用 ARWorldMap,能解决使用者再次进入同一物理空间时的AR 场景恢复问题,也能在多人之间共桌AR 体验,但这种共享并不是实时的,在载入ARWorldMap 后,设备新检测到的环境信息和使用者所做操作不会实时共享,即在载入ARWorldMap后,用户A 所做的操作或者添加的虚拟物体不会在用户B的设备上体现。
为解决这个问题,ARKit 3. 0 就提出了协作 Session (Collaborative Session)的概念,协作 Session 利用Multipeer Connectivity 近距离通信或者其他网络通信方法,通过实时共享 ARAnchor 的方式达到 AR体验实时共享的目的。
ARWorldMap 通过地标(Landmark 也即是特征值信息)来恢复与更新用户姿态,ARWorldMap 也通过一系列的 ARAnchor 来连接虚实,并在 ARAnchor 下挂载虚拟物体。但在ARWorldMap 中,这些数据并不是实时更新的,即在ARWorldMap 生成之后用户新检测到的地标及所做的操作并不会共享,其他人也无法看到变更后的数据。在 ARWorldMap 之外用户新检测到的地标或者新建的 ARAnchor 并不会被共享,因此,AR WorldMap 只适用于一次性的数据共享,并不能做到实时交互共享。
协作 Session 的出现就是为了解决这个问题,协作 Session 可以实时地共享 AR体验,持续性地共享ARAnchor 及环境理解相关信息,利用 Multipeer Connectivity 近距离通信框架,所有用户都是平等的,没有主从的概念,因此,新用户可以随时加入,老用户也可以随时退出,这并不会影响其他人的体验,也不会中断共享进程。实时共享意味着在整个协作 Session 过程中,任何一个用户做的变更都可以即时地反馈到所有参与方场景中,如一个用户新添加了一个 ARAnchor,其他人可以即时地看到这个 ARAnchor。通过协作Session 可以营造持续性的、递进的AR体验,可以构建无中心、多人AR应用,并且所有的物理仿真、场景变更、音效都会自动进行同步。
在协作 Session设计时,为了达到去中心、实时共享目标,ARKit 团队将环境检测分成两部分进行处理,一部分用于存储用户自身检测到的环境地标及创建的 ARAnchor 等信息,叫作Local Map,另一部分用于存储其他用户检测到的环境地标及创建的 ARAnchor 等信息,叫作 External Map。
下面以两个用户使用协作 Session 共享为例进行说明,在刚开始时,用户1与用户2各自进行环境检测与 ARAnchor 操作,这时他们相互之间没有联系,有各自独立的坐标系,如图8-7所示。在AR 应用进程中,用户1检测到的环境地标及创建的 ARAnchor 等信息(这些信息称为 Collaboration Data)会不断地实时共享给用户2,用户2会在其 External Map 里存储这些信息,反之亦然,用户1也会在其 External Map 里存储用户2检测到的环境地标及创建的 ARAnchor 等信息。随着探索的进一步推进,当用户1与用户2检测到的地标及 ARAnchor 有共同之处时(即有匹配的特征点),如图8-8所示,ARKit 会根据这些三维地标及ARAnchor信息解算出用户1与用户2之间的坐标转换关系,并且定位他们相互之间的位置关系。如果ARKit 解算成功,这时,用户1的Local Map 会与其External Map 融合成新的Local Map,即用户2探索过的环境会成为用户1环境理解的一部分,用户2也会进行同样的操作。这个过程大大地扩展了用户1与用户2的环境理解范围,即用户2 环境探索的部分也已成为用户1环境探索的一部分,用户1无须再去探索用户2已探索过的环境,对用户2亦是如此。因为此时环境信息已经进行了融合,用户1 自然就可以看到用户2 创建的 ARAnchor了。
需要注意的是,虽然环境探索部分进行了融合,但是用户1与用户2的世界坐标系仍然是独立的。然而由于 ARAnchor 是相对于特定Local Map,在进行环境融合时 ARKit 已经解算出了之间的坐标转换关系,所以就能够在真实世界中唯一定位这些 ARAnchor。
在图8-9中可以看到,使用协作 Session 的第一步是设置并建立网络连接,网络连接可以使用 MultipeerConnectivity 近距离通信框架,也可以使用任何其他可信的网络通信框架。在建立网络连接之后,需要启用协作 Session 功能,AR WorldTrackingConfiguration 配置类提供了一个isCollaborationEnabled 属性,该属性为布尔值类型,设置 true 即可启动协作 Session 功能。
在 AR 应用运行时,ARKit 会周期性调用 session(_:didOutputCollaborationData:)方法,通过这个方法就可以将 AR运行时数据(Collaboration Data)共享给其他用户。但需要注意的是,这些 Collaboration Data数据会周期性地产生并积累,但不会自动发送,AR应用应当及时将这些数据发送给所有其他参与方进行共享,其他用户接收到 Collaboration Data 数据后,需要进行反序列化,并使用 update(with:)方法应用到ARSession 中。数据产生、发送、接收这个过程会在整个协作 Session 中持续进行,通过实时地数据分发、更新,就能够实现实时多用户的 AR共享
在整个协作 Session 中,ARAnchor 起着非常重要的作用,通过实时网络传输,ARAnchor 在整个网络中生命周期是同步的,即用户1创建一个 ARAnchor后用户2可以实时地看到,用户1销毁一个 ARAnchor,用户2也会同步移除这个 ARAnchor。除此之外,每一个 ARAnchor 都有一个 Session Identifier 值,通过这个 Session Identifier 值就可以知道这个 ARAnchor 的创建者,在应用中,可以利用这个属性区别处理自己创建的 ARAnchor 和别人创建的ARAnchor,只有自己创建的 ARAnchor 才需要共享。
在协作 Session 中,只有用户自己人工创建的 ARAnchor 会被共享,包括用户自己创建的子级ARAnchor,其他的如 ARImageAnchor、ARObjectAnchor、ARPlaneAnchor 等系统自动创建的锚点则不会被共享(此类锚点遵循 ARTrackable 协议)。
在协作 Session 中,参与用户的位置信息非常关键,因为这涉及坐标系的转换及虚拟物体的稳定性,因此,ARKit 专门引人了一个 ARParticipantAnchor用于定位和描述用户信息。当用户接收并融合其他用户的数据后,ARKit会解算出用户之间的相互关系,最重要的就是坐标系转换关系。为直观地描述相互关系并减少运算,ARKit 会创建 ARParticipantAnchor 用于描述其他用户在自己世界坐标系中的位置与姿态。
同时,为了实时精确捕捉其他用户的位置与姿态,ARParticipantAnchor 每帧都会更新。与所有其他可跟踪对象一样,每一个 ARParticipantAnchor 都有一个独立且唯一的 Identifier 值,ARParticipantAnchor 可以随时被添加、更新、移除,用于及时反映协作 Session 中参与者的加入、更新和退出。ARParticipantAnchor 会在协作 Session 中 Local Map 与 External Map 融合时创建,因此,ARParticipantAnchor 可以看作 AR 共享正常运行的标志。正是通过ARParticipantAnchor 与 ARAnchor,参与者都能在正确的现实环境位置中看到一致的虚拟物体。
通过前面的讲述我们可以看到,共享体验在参与者都探索到公共的地标及 ARAnchor 后开始(通俗地讲就是手机扫描到公共的物理环境),但在不同的设备上匹配公共地标受很多因素影响,如角度、光照、遮挡等,正确快速匹配并不是一件简单的事情,因此,为更快地开始共享体验,参与者最好以相同的摄像机视角扫描同一片物理场景开始,如图8-10所示。另外最好确保当前 ARFrame. WorldMappingStatus 处于mapped 状态,这可以确保参与者看到的三维地标及时保存进 L.ocal Map 或 External Map 中,其他参考者可以本地化(Localize)这些三维坐标并更好地进行匹配,从而开始 AR 共享进程,除此之处,也可以检查这个属性以获取当前协作 Session工作状态。