You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 12:00:03