【iOS ARKit】RealityKit 同步机制

     协作 Session 可以很方便地实现多用户之间的AR体验实时共享,但开发者需要自行负责并确保AR场景的完整性,自行负责虚拟物体的创建与销毁。为简化同步操作,RealityKit 内建了同步机制,RealityKit 同步机制基于 Multipeer Connectivity,当设置好 MultipeerConnectivityService 属性之后,RealityKit 会自动在参与者之间同步实体对象(Entity)。

RealityKit 同步服务机制

      在 RealityKit 中,组成场景(Scene)的基本元素是实体(Entity),实体由其所挂载的组件(Component)定义外观和行为,RealityKit 所有的实体类都继承自 Entity 基类,如 AnchorEntity、ModelEntity,Entity 基类包含了两个组件:Transtorm 组件和 Synchronization 组件,Transform 组件用于空间定位,而Synchronization 组件用于同步。因此,RealityKit 中所有的实体对象都默认带有 Synchronization 组件,即都可以通过网络进行同步,这也是 RealityKit 同步的技术基础。

    虽然 RealityKit 网络数据传输仍然依赖于 Multipeer Connectivity,但相对于协作 Session,在 RealityKit中,开发人员不再需要自行处理数据的发送与接收处理工作,RealityKit 会自动进行相关操作,从而大大简化了开发流程。

    使用 RealityKit 的同步服务功能只需要两步操作:(1)使用 Multipeer Connectivity 设置好 MCSession,并生成一个 MultipeerConnectivityService 对象。(2) 将生成的 MultipeerConnectivityService 对象赋给 ARView.scene 的 synchronizationService 属性,场景中所有的实体对象都将继承该值。在进行这两步操作之后,后续的所有同步操作完全由 RealityKit 自动处理,使用 RealtiyKit 同步服务的完整代码如下所示,稍后我们会对代码进行详细解析。

//
//  SyncARSession.swift
//  ARKitDeamo
//
//  Created by zhaoquan du on 2024/2/28.
//import SwiftUI
import ARKit
import RealityKit
import MultipeerConnectivitystruct SyncARSession: View {static var arView: ARView!static var multipeerSession: MultipeerSession?var body: some View {SnycARSessionContent().onDisappear {SyncARSession.arView.session.delegate = nilSyncARSession.arView.session.pause()SyncARSession.arView = nilSyncARSession.multipeerSession?.endConnect()SyncARSession.multipeerSession = nilprint("SyncARSession onDisappear")}.edgesIgnoringSafeArea(.all).navigationTitle("ARSession同步")}}struct SnycARSessionContent: UIViewRepresentable {func makeUIView(context: Context) -> some ARView {let arView = ARView(frame: .zero)arView.automaticallyConfigureSession = falselet config = ARWorldTrackingConfiguration()config.planeDetection = .horizontalconfig.isCollaborationEnabled = truearView.session.run(config,options: [.resetTracking,.removeExistingAnchors])arView.session.delegate = context.coordinatorSyncARSession.arView = arViewcontext.coordinator.createPlane()context.coordinator.addGesture()return arView}func updateUIView(_ uiView: UIViewType, context: Context) {}func makeCoordinator() -> Coordinator {Coordinator()}class Coordinator: NSObject,ARSessionDelegate {var arView: ARView? {return SyncARSession.arView}var multipeerSession: MultipeerSession? {return SyncARSession.multipeerSession}var planeEntity : ModelEntity? = nilvar raycastResult : ARRaycastResult?func createPlane(){SyncARSession.multipeerSession = MultipeerSession(serviceType: "sync-session",receivedDataHandler: receiveData(data:from:), peerJoinedHandler: peerJoined(_:), peerLeftHandler: peerLeft(_:), peerDiscoveredHandler: peerDiscovered(_:))let planeMesh = MeshResource.generatePlane(width: 0.15, depth: 0.15)let planeMaterial = SimpleMaterial(color:.white,isMetallic: false)planeEntity = ModelEntity(mesh: planeMesh, materials: [planeMaterial])let planeAnchor = AnchorEntity(plane: .horizontal)planeAnchor.synchronization = nildo {let planeMesh = MeshResource.generatePlane(width: 0.15, depth: 0.15)var planeMaterial = SimpleMaterial(color: SimpleMaterial.Color.red, isMetallic: false)planeMaterial.color =  try SimpleMaterial.BaseColor(tint:UIColor.yellow.withAlphaComponent(0.9999), texture: MaterialParameters.Texture(TextureResource.load(named: "AR_Placement_Indicator")))planeEntity = ModelEntity(mesh: planeMesh, materials: [planeMaterial])planeAnchor.addChild(planeEntity!)arView?.scene.addAnchor(planeAnchor)arView?.scene.synchronizationService = multipeerSession?.syncService} catch let error {print("加载文件失败:\(error)")}}func randomColor() -> UIColor{return UIColor(red:CGFloat(arc4random()%256)/255.0,green:CGFloat(arc4random()%256)/255.0,blue: CGFloat(arc4random()%256)/255.0,alpha: 1.0 )}func addGesture(){let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))arView?.addGestureRecognizer(tap)}@objc func handleTap(_ sender: UITapGestureRecognizer? = nil) {guard let raycastResult = raycastResult else {print("还未检测到平面")return}let box = ModelEntity(mesh: MeshResource.generateBox(size: 0.1), materials: [SimpleMaterial.init(color: randomColor(), isMetallic: false)])box.position = [0,0.05,0]let anchorEntity = AnchorEntity(raycastResult: raycastResult)anchorEntity.addChild(box)arView?.scene.addAnchor(anchorEntity)}//ARSessionDelegatefunc session(_ session: ARSession, didUpdate frame: ARFrame) {guard let arView = arView, let result = arView.raycast(from: arView.center, allowing: .estimatedPlane, alignment: .horizontal).first else{return}raycastResult = resultplaneEntity?.setTransformMatrix(result.worldTransform, relativeTo: nil)}func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {}func receiveData(data:Data,from peer: MCPeerID){}func peerDiscovered(_ peer: MCPeerID) -> Bool {guard let multipeerSession = multipeerSession else {return false}if multipeerSession.connectedPeers.count > 3 {return false}else{return true}}func peerJoined(_ peer: MCPeerID) {}func peerLeft(_ peer: MCPeerID) {}}
}#Preview {SyncARSession()
}

     代码比上一节代码中的代码要清爽很多,一方面是RealityKit 的同步服务机制简化了人工干预,代码详细功能如下:

   (1) 初始化 Multipeer Session 类,设置 RealityKit 的同步服务。

   (2)进行平面检测,在检测到可用平面时实例化一个指示图标用于指示放置位置。

   (3)添加屏幕单击手势,在平面可用时单击屏幕会在指示图标位置放置一个颜色随机的立方体。

     在第(1)项功能中,即 createPlane()方法中的代码,除了在检测到平面时创建一个指示图标,还初始化了

MultipeerSession 类,传入的是一个用于区分网络服务的 serviceName,然后使用语句 self.scene. synchronizationService = multipeerSession?.syncService设置 RealityKit 的同步服务功能。

     在第(3)项功能中,即 handTap()方法中代码,我们直接在指示图标位置生成了一个颜色随机的立方体。

     需要注意的是,这里并没有生成 ARAnchor 对象,因为在 RealityKit 中,所有的 AnchorEntity 类都会自动进行同步。

     在两台设备 A和B上同时运行本案例(确保两台设备连接到同一个WiFi网络或者都打开蓝牙),在A设备检测到的平面上单击添加立方体,在A、B 连接顺畅的情况下可以看到B设备也会同步出现该立方体,并且立方体所在物理世界中的位置与A设备中的一致,同理,在B设备检测到的平面上单击添加立方体,A设备也会同步出现该立方体,并且立方体所在物理世界中的位置与B设备中的一致,效果如图所示。

使用 RealityKit 同步服务注意事项

    Reality Kit 同步服务让 AR体验实时共享变得前所未有地方便,虚拟元素可以实时地共享到所有参与方,而这主要归功于 Synchronization组件,该组件的主要功能就是通过网络在不同设备间实时同步实体对象,其主要属性有俩个。identifierisOwner:每一个实体对象在网络中的唯一标识符布尔值,用于标识本设备是否拥有该实体对象的所有权。ownershipTransferMode:所有权转移类型,为 SynchronizationComponent. OwnershipTransferMode 枚举值,该枚举共有两个值:autoAccept 为自动授受所有权转移;manual需要使用者进行所有权转移授权。

    可以看出,Synchronization 组件可以对实体对象进行非常严格的所有权控制,防止不经授权对其他设备生成的实体对象进行操作。所有权是 Synchronization 组件中重要的概念,每一个创建实体对象的ARSession 拥有对该实体对象的所有权,只有实体对象的所有者才有权修改该实体对象(如修改尺寸、修改材质、旋转、移动等),修改结果尔后会同步到所有参与者。非实体对象所有者可以修改其本机场景中的实体对象,但无法同步到其他参与者,如果需要同步修改结果,可以向实体对象所有者申请授权,得到授权后就可以成为该实体对象的所有者,修改结果可以同步到所有的参与者,如图8–16所示。

     RealityKit 这么处理的原因是为了防止未授权用户擅自修改其他参与方场景中的虚拟元素,影响其他人的使用体验,保证共享场景中的虚拟元素放置都符合预期。在图8-16中,假设用户①与用户②已经通过 RealityKit 的同步服务进行了同步,①号立方体由用户①创建,②号立方体由用户②创建,这时用户①与用户②都可以看到这两个立方体,此时用户①可以对①号立方体进行任何修改,修改结果会实时地同步到用户②,用户①也可以对②号立方体进行修改,但修改结果并不会被同步。

   

     如果用户①希望能修改②号立方体并且同步到用户②,那么用户①可以申请所有权,在用户②同意授权后,用户①对②号立方体所作的修改就能够同步到用户②。需要注意的是,这时②号立方体的所有权已经转移到用户①,如果用户②要对②号立方体进行修改操作,用户②也需要向用户①申请授权,即一个实体对象的所有者在同一时刻只有一个。进行实体对象操控授权的典型代码如下所示。

public extension HasSynchronization {func EntityManipulation() {if isOwner {//拥有某个实体的所有权,可以进行处理} else {requestOwnership { failure inif failure == .granted {//没有某个实体的所有权,进行所有权申请,得到授权后可以进行处理}}}}/// Execute the escaping completion if you are the entity owner, once you receive ownership/// or call result failure if ownership cannot be granted to the caller./// - Parameter completion: completion of type Result, success once ownership granted, failure if not grantedfunc runWithOwnership(completion: @escaping (Result<HasSynchronization, Error>) -> Void) {if self.isOwner {// If caller is already the ownercompletion(.success(self))} else {self.requestOwnership { (result) inif result == .granted {completion(.success(self))} else {completion(.failure(result == .timedOut ?MHelperErrors.timedOut :MHelperErrors.failure))}}}}}

    在代码中,对实体对象进行操作时,首先检查是否拥有该实体对象的所有权,如果有则进行操作,如果没有则向实体对象所有者申请授权,如果授权申请通过则可以进行相应操作。

     实体对象所有者可以设置实体授权模式,RealityKit 支持两种实体授权模式,其值由SynchronizationComponent. OwnershipTransferMode 枚举定义,该枚举共有两个枚举值:autoAccept(自动授权)和 manual(手动授权)。默认授权模式为 autoAccept,即实体对象所有权会自动授权给任何参与者对该实体的所有权申请。设置为 manual 时,当有参与者申请所有权时会触发 SynchronizationEvents.OwnershipRequest 事件,我们需要在该事件的accept()回调方法中对授权进行自定义处理,事件处理可参阅第2章相关内容。

     在一些场合下,我们可能不想某些实体对象或者某些操作被共享,这时候可以将该实体对象的同步组件设置为nil,设置为 nil 的实体对象及其子对象将不会被共享。

具体代码地址:GitHub - duzhaoquan/ARkitDemo

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

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

相关文章

Python标准库sys常用函数、方法及代码实战解析【第108篇—标准库sys常用函数】

Python标准库sys常用函数、方法及代码实战解析 在Python的标准库中&#xff0c;sys 模块是一个常用而强大的工具&#xff0c;它提供了与Python解释器交互的函数和变量。本文将介绍sys模块的一些常用函数和方法&#xff0c;并通过实际的代码实例来解析它们的用法。 1. sys.argv…

2024.2.19

1.TCP模型 服务器端 #include <myhead.h> #define SER_IP "192.168.199.129" #define SER_PORT 8899int main(int argc, const char *argv[]) {//1.创建用于连接的套接字文件int sfdsocket(AF_INET,SOCK_STREAM,0);if(sfd-1){perror("socket error"…

react 原理揭秘

1.目标 A. 能够知道setState()更新数据是异步的 B. 能够知道JSX语法的转化过程 C. 能够说出React组件的更新机制 D. 能够对组件进行性能优化 E. 能够说出虚拟DOM和Diff算法 2.目录 A. setState()的说明 B. JSX语法的转化过程 C. 组件更新机制 D. 组件性能优化 E. 虚拟DOM和D…

[Vulnhub]靶场 Web Machine(N7)

kali:192.168.56.104 主机探测: arp-scan -l 靶机ip:192.168.56.104 端口扫描 nmap -p- 192.168.56.106 看一下web 目录扫描 gobuster dir -u http://192.168.56.106 -x html,txt,php,bak,zip --wordlist/usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt exp…

【QT 5 +Linux下软件qt软件打包+qt生成软件创建可以安装压缩包+学习他人文章+第三篇:学习打包】

【QT 5 Linux下软件qt软件打包qt生成软件创建可以安装压缩包学习他人文章第三篇&#xff1a;学习打包】 1、前言2、实验环境3、自我学习总结-本篇总结&#xff08;1&#xff09;了解安装包的目录结构&#xff08;2&#xff09;了解要编写文件与编写脚本1. control文件2. postin…

NVMFS5113PLWFT1G汽车级功率MOSFET 60V 10A/64A满足AEC-Q101标准

AEC-Q101认证标准详细解读&#xff1a; AEC-Q101是一种汽车电子元件可靠性标准&#xff0c;由汽车电子委员会&#xff08;Automotive Electronics Council&#xff0c;简称AEC&#xff09;制定。该标准旨在确保在汽车环境中使用的电子元件具有足够的可靠性和耐久性。 AEC-Q10…

探索JavaScript中的构造函数,巩固你的JavaScript基础

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

element-ui附件上传及在线查看详细总结,后续赋源码

一、附件上传 1、在element-ui上面复制相应代码 a、accept"image/*,.pdf,.docx,.xlsx,.doc,.xls" 是规定上传文件的类型&#xff0c;若是不限制&#xff0c;可以直接将accept‘all即可&#xff1b; b、:action"action" 这个属性就是你的上传附件的地址&am…

如何解决局域网tcp延迟高来进行安全快速内外网传输呢?

在当今企业运营中&#xff0c;数据的快速流通变得至关重要&#xff0c;但局域网内的TCP延迟问题却成为了数据传输的障碍。本文旨在分析局域网TCP延迟的成因&#xff0c;并探讨几种企业数据传输的常见模式&#xff0c;以及如何为企业选择合适的传输策略&#xff0c;以确保数据在…

java之servlet

动态的web资源开发技术 不同的用户&#xff0c;或者携带不同的参数&#xff0c;访问服务器 服务器添加判断层&#xff0c;实现访问不同的web资源

【iOS ARKit】协作 Session 实例

协作 Session 使用注意事项 协作 Session 是在 ARWorldMap 基础上发展起来的技术&#xff0c;ARWorldMap 包含了一系列的地标、ARAnchor 及在观察这些地标和 ARAnchor 时摄像机的视场&#xff08;View&#xff09;。如果用户在某一个位置新创建了一个 ARAnchor&#xff0c;这时…

禅道安装与使用

文章目录 1.下载2.安装 1.下载 进入禅道官网下载 2.安装 登录后

uniapp生成app包引导用户开启通知权限和热更新

uniapp生成app包引导用户开启通知权限和热更新 引导用户开启通知权限 export function setPermissions() {// #ifdef APP-PLUS if (plus.os.name Android) {var main plus.android.runtimeMainActivity();var pkName main.getPackageName();var uid main.getApplicationI…

【免费】两阶段鲁棒优化matlab实现——CCG和benders

目录 1 主要内容 2 部分代码 3 程序结果 4 下载链接 1 主要内容 程序采用matlab复现经典论文《Solving two-stage robust optimization problems using a column-and-constraint generation method》算例&#xff0c;实现了C&CG和benders算法两部分内容&#xff0c;通过…

1.3 vue ui框架-element-ui框架

1 前言 ElementUI是一套基于VUE2.0的桌面端组件库&#xff0c;ElementUI提供了丰富的组件帮助开发人员快速构建功能强大、风格统一的页面。 ElementUI官网 https://element.eleme.io 2 安装 运行命令 cnpm i element-ui -S -S表示只在该项目下安装&#xff0c;不是全局安…

基于YOLOv8深度学习的复杂场景下船舶目标检测系统【python源码+Pyqt5界面+数据集+训练代码】深度学习实战、目标检测

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

GL绘制自定义线条4_使用OpenGL ES实现钢笔效果

在以前的文章里http://t.csdnimg.cn/TgCtl&#xff0c;我简述了如何使用OpenGL ES实现光滑的粗线条的绘制效果&#xff0c;在闲暇时间我把它再进一步进化&#xff0c;实现了端点长度按照压感大小实现伸缩的逻辑&#xff0c;从而实现了如下的笔锋效果&#xff1a; 书写过程中的效…

包管理工具之npm也慌了?

起因 因为npm的种种问题,我很早就换成了pnpm和yarn(但是其实npm也在使用),已经很久没有关注npm的功能更新了。最近无意间进入Node18版本的安装目录,发现其除了常规的node,npm等默认安装了一个新的包corepack,这个就是今天我要分享的东西了。 注: 我因为18版本的node上…

【STM32】STM32学习笔记-FLASH闪存(48)

00. 目录 文章目录 00. 目录01. FLASH简介02. 闪存模块组织03. FLASH基本结构04. FLASH解锁05. 使用指针访问存储器06. 程序存储器编程07. 选项字节08. 选项字节编程09. 选项字节擦除10. 器件电子签名11. 附录 01. FLASH简介 STM32F1系列的FLASH包含程序存储器、系统存储器和选…

灰度负载均衡和普通负载均衡有什么区别

灰度负载均衡&#xff08;Gray Load Balancing&#xff09;与普通负载均衡的主要区别在于它们服务发布和流量管理的方式。 灰度负载均衡 目的&#xff1a;主要用于灰度发布&#xff0c;即逐步向用户发布新版本的服务&#xff0c;以减少新版本可能带来的风险。工作方式&#x…