跟踪多个图像并在 ARkit2 中播放它们的视频

Tracking multiple images and play their videos in ARkit2

我有下面的示例代码,跟踪单个图像然后使用 Apple 的 ARkit 播放视频。 当前视频存储在设备本地。 下面的代码只跟踪单个图像并播放相应的视频。 我如何修改它并让它跟踪多个图像并播放它们的视频?

 @IBOutlet var sceneView: ARSCNView!

// Create video player
let videoPlayer: AVPlayer = {
    // Load cat video from bundle
    guard let url = Bundle.main.url(forResource: "nyan-cat", withExtension: "mp4", subdirectory: "art.scnassets") else {
        print("Could not find video file")
        return AVPlayer()
    }

    let player = AVPlayer(url: url)

    NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil, queue: nil) { notification in
        player.seek(to: CMTime.zero)
        player.play()
    }
    return player
}()

func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
    let node = SCNNode()

    // Show video overlayed to image
    if let imageAnchor = anchor as? ARImageAnchor {

        // Create a plane
        let plane = SCNPlane(width: imageAnchor.referenceImage.physicalSize.width,
                             height: imageAnchor.referenceImage.physicalSize.height)

        // Set AVPlayer as the plane's texture and play
        plane.firstMaterial?.diffuse.contents = self.videoPlayer
        self.videoPlayer.play()

        let playNode = SCNNode(geometry: plane)

        // Rotate the plane to match the anchor
        playNode.eulerAngles.x = -.pi / 2

        // Add plane node to parent
        node.addChildNode(playNode)
    }

    return node
}

您必须在 ARConfiguration 上设置 maximumNumberOfTrackedImages。

Setting the maximum number of tracked images will limit the number of images that can be tracked in a given frame. If more than the maximum is visible, only the images already being tracked will continue to track until tracking is lost or another image is removed. Default value is one.

        configuration.maximumNumberOfTrackedImages = 2

正如@SilentK 所说,为了跟踪多个 ARImageAnchors,您需要设置要跟踪的最大图像数,例如:

configuration.maximumNumberOfTrackedImages = 10

IOS12 开始,ARWorldTrackingConfigurationARImageTrackingConfiguration 都可用。

正如您所知,当您将 ARReferenceImage 添加到 Assets Bundle 时,您必须为其分配一个 name,例如:

现在由于每个目标都包含一个唯一的名称,您可以轻松地使用它来加载您的不同视频。因此,将每个视频命名为与您的 imageTarget 相同的名称是最有意义的。

您尝试执行的操作的示例可能如下所示:

//-------------------------
//MARK: - ARSCNViewDelegate
//-------------------------

extension ViewController: ARSCNViewDelegate{

    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {

        //1. Check We Have Detected An ARImageAnchor
        guard let validAnchor = anchor as? ARImageAnchor else { return }

        //2. Create A Video Player Node For Each Detected Target
        node.addChildNode(createdVideoPlayerNodeFor(validAnchor.referenceImage))

    }


    /// Creates An SCNNode With An AVPlayer Rendered Onto An SCNPlane
    ///
    /// - Parameter target: ARReferenceImage
    /// - Returns: SCNNode
    func createdVideoPlayerNodeFor(_ target: ARReferenceImage) -> SCNNode{

        //1. Create An SCNNode To Hold Our VideoPlayer
        let videoPlayerNode = SCNNode()

        //2. Create An SCNPlane & An AVPlayer
        let videoPlayerGeometry = SCNPlane(width: target.physicalSize.width, height: target.physicalSize.height)
        var videoPlayer = AVPlayer()

        //3. If We Have A Valid Name & A Valid Video URL The Instanciate The AVPlayer
        if let targetName = target.name,
            let validURL = Bundle.main.url(forResource: targetName, withExtension: "mp4", subdirectory: "/art.scnassets") {
            videoPlayer = AVPlayer(url: validURL)
            videoPlayer.play()
        }

        //4. Assign The AVPlayer & The Geometry To The Video Player
        videoPlayerGeometry.firstMaterial?.diffuse.contents = videoPlayer
        videoPlayerNode.geometry = videoPlayerGeometry

        //5. Rotate It
        videoPlayerNode.eulerAngles.x = -.pi / 2

        return videoPlayerNode

    }

}

如果您渲染了多个实例,使用此方法的无限循环播放非常CPU密集:

 NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil, queue: nil) { notification in
        player.seek(to: CMTime.zero)
        player.play()
    }

因此,您可能希望添加一次只播放一个视频的逻辑,例如在 VideoNode 上执行 SCNHitTest,这将触发它播放等

希望对您有所帮助...