ARKit Xcode开发:实现锚定识别目标的AR视频切换至全屏播放功能
AR图像识别视频播放+全屏切换功能整合方案
前置修改:修复现有代码问题+新增全局状态
你现有代码里存在语法错误:把renderer(_:didUpdate:for:)代理方法嵌套在了nodeFor方法内部,会导致该方法无法正常触发,需要先把它移到类层面作为独立方法。
在你的ViewController类中新增3个全局属性,用来管理播放状态:
// 绑定界面上的模式切换开关/按钮,标记当前是否为全屏播放模式 var isFullScreenMode = false // 记录当前正在播放的视频播放器实例 var currentActivePlayer: AVPlayer? // 存储全屏播放的图层,方便切换模式时移除 var fullScreenPlayerLayer: AVPlayerLayer?
步骤1:修改AR识别后的主逻辑
替换你原来的renderer(_:nodeFor:)方法代码如下,会自动根据当前的播放模式走对应的渲染逻辑:
public func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? { let node = SCNNode() // 校验是不是图像识别锚点 guard let imageAnchor = anchor as? ARImageAnchor, let targetName = imageAnchor.referenceImage.name else { return nil } // 先暂停所有播放器、移除旧的全屏图层,避免多个视频同时播放 [adamoquadVideoPlayer, noeVideoPlayer, moseVideoPlayer, giuseppeVideoPlayer].forEach { $0.pause() } fullScreenPlayerLayer?.removeFromSuperlayer() // 非全屏模式走AR平面渲染逻辑 if !isFullScreenMode { // 创建和识别目标等大的平面 let plane = SCNPlane( width: imageAnchor.referenceImage.physicalSize.width, height: imageAnchor.referenceImage.physicalSize.height ) // 根据识别到的目标匹配对应的播放器 switch targetName { case "01ADAMOTARGET": currentActivePlayer = adamoquadVideoPlayer case "02GIOSUETARGET": currentActivePlayer = noeVideoPlayer case "04CAINOTARGET": currentActivePlayer = moseVideoPlayer case "03GIUSEPPETARGET": currentActivePlayer = giuseppeVideoPlayer default: break } // 把播放器设置为平面纹理并播放 plane.firstMaterial?.diffuse.contents = currentActivePlayer currentActivePlayer?.play() // 平面旋转贴合识别目标 let planeNode = SCNNode(geometry: plane) planeNode.eulerAngles.x = -.pi / 2 node.addChildNode(planeNode) return node } else { // 全屏模式下直接播放全屏视频,不需要生成AR节点 playFullScreenVideo(for: targetName) return nil } }
步骤2:抽离全屏播放公共方法
把你原来的全屏播放逻辑抽成独立方法,方便识别目标和点击切换按钮时复用:
/// 根据识别到的目标名称播放对应全屏视频 func playFullScreenVideo(for targetName: String) { // 先重置播放状态 [adamoquadVideoPlayer, noeVideoPlayer, moseVideoPlayer, giuseppeVideoPlayer].forEach { $0.pause() } fullScreenPlayerLayer?.removeFromSuperlayer() // 匹配对应播放器 switch targetName { case "01ADAMOTARGET": currentActivePlayer = adamoquadVideoPlayer case "02GIOSUETARGET": currentActivePlayer = noeVideoPlayer case "04CAINOTARGET": currentActivePlayer = moseVideoPlayer case "03GIUSEPPETARGET": currentActivePlayer = giuseppeVideoPlayer default: break } guard let player = currentActivePlayer else { return } // 添加全屏图层播放 let layer = AVPlayerLayer(player: player) layer.frame = view.bounds view.layer.addSublayer(layer) fullScreenPlayerLayer = layer player.play() }
步骤3:实现模式切换按钮逻辑
给你界面上的开关/按钮添加点击事件,切换时会无缝衔接当前播放进度:
@IBAction func togglePlayMode(_ sender: UISwitch) { isFullScreenMode = sender.isOn // 没有正在播放的视频时直接返回 guard let currentPlayer = currentActivePlayer else { return } // 记录当前播放进度,实现无缝切换 let currentTime = currentPlayer.currentTime() currentPlayer.pause() if isFullScreenMode { // 切到全屏模式 fullScreenPlayerLayer?.removeFromSuperlayer() let layer = AVPlayerLayer(player: currentPlayer) layer.frame = view.bounds view.layer.addSublayer(layer) fullScreenPlayerLayer = layer // 可选:隐藏AR视图避免画面重叠 // arView.isHidden = true } else { // 切回AR模式 fullScreenPlayerLayer?.removeFromSuperlayer() // arView.isHidden = false } // 从原来的进度继续播放 currentPlayer.seek(to: currentTime) currentPlayer.play() }
步骤4:修复AR跟踪更新逻辑
把原来嵌套的renderer(_:didUpdate:for:)方法移到类层面,修改为全屏模式下不受跟踪状态影响:
public func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) { // 全屏模式下不受AR跟踪影响,视频持续播放 guard !isFullScreenMode, let imageAnchor = anchor as? ARImageAnchor, let targetName = imageAnchor.referenceImage.name else { return } // 仅当当前播放的视频和识别目标对应时,根据跟踪状态控制播放 switch targetName { case "01ADAMOTARGET" where currentActivePlayer === adamoquadVideoPlayer: imageAnchor.isTracked ? adamoquadVideoPlayer.play() : adamoquadVideoPlayer.pause() case "02GIOSUETARGET" where currentActivePlayer === noeVideoPlayer: imageAnchor.isTracked ? noeVideoPlayer.play() : noeVideoPlayer.pause() case "04CAINOTARGET" where currentActivePlayer === moseVideoPlayer: imageAnchor.isTracked ? moseVideoPlayer.play() : moseVideoPlayer.pause() case "03GIUSEPPETARGET" where currentActivePlayer === giuseppeVideoPlayer: imageAnchor.isTracked ? giuseppeVideoPlayer.play() : giuseppeVideoPlayer.pause() default: break } }
逻辑说明
- 全屏模式下不管是否能识别到目标,视频都不会暂停,完全和AR跟踪解绑
- 切换模式时会保留当前播放进度,不会重新开始播放
- 识别到新的目标时会自动暂停旧视频、播放新目标对应的视频,符合原有需求
内容的提问来源于stack exchange,提问作者arcsander
相关产品推荐
相关产品推荐

