[Swift, ARKit] Lire la vidéo sur plusieurs écrans à l'aide des avions détectés

L'ARKit de Swift a la capacité de détecter les avions. Je pense que l'utilisation générale est de colorer le plan détecté ou de le toucher pour placer un autre modèle 3D, mais cette fois, j'utiliserai cet avion tel quel comme écran pour lire la vidéo comme un téléviseur. C'était.

Comme un flux Détecter un avion et placer une ancre de voie ARP ↓ Créer SCNPlane lorsque ARPlaneAnchor est placé ↓ Collez la vidéo dans SCNPlane et lisez-la ↓ Créer un nœud SCN basé sur la voie SCN C'est. J'ai trouvé certaines choses que j'ai créées moi-même ARPlane et ARBox et collé la vidéo, mais aucune n'a détecté l'avion et n'a cessé d'augmenter ARPlane dynamiquement, alors je vais l'essayer.

Environnement de vérification

J'ai utilisé les vidéos suivantes pour lire. Il a été créé par l'entreprise auparavant. Comme il est un peu long, je n'ai découpé que la partie qui a donné l'exemple de l'échec à partir de 78 secondes. https://youtu.be/4xfmPCFUplU?t=78

résultat

Puisque le code source est long, d'abord à partir du résultat. Vous pouvez faire quelque chose comme ça. result.gif D'après le résultat, tout s'est bien passé. Les tables, chaises, murs, etc. sont détectés comme des surfaces planes et des vidéos sont collées à chaque fois. Comme cela sera décrit plus loin, il semble qu'il puisse être changé en carré ou verticalement long si la taille remplit les conditions. C'est un peu déroutant, mais vous pouvez également voir que chaque vidéo est lue indépendamment. ** À propos, puisqu'il s'agit d'une vidéo, l'audio sera également lu. Et comme chaque vidéo est indépendante, plusieurs sons peuvent voler à des moments différents. ** ** Comme je l'ai dit, j'ai une forte couleur de lavage de cerveau.

Code source

Le code source complet est ci-dessous. L'explication grossière est commentée.

ViewController.swift


import ARKit

class ViewController: UIViewController, ARSCNViewDelegate {
    
    @IBOutlet weak var scnView: ARSCNView!
    
    var videoURL: URL!
    
    override var prefersStatusBarHidden: Bool { return true }
    override var prefersHomeIndicatorAutoHidden: Bool { return true }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.scnView.scene = SCNScene()
        self.scnView.delegate = self
        //Obtenez l'URL de la vidéo à lire
        self.videoURL = Bundle.main.url(forResource: "pien", withExtension: "mp4")!
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        let configuration = ARWorldTrackingConfiguration()
        //Réglez la détection de plan sur horizontal et vertical
        configuration.planeDetection = [.vertical, .horizontal]
        configuration.isLightEstimationEnabled = true
        self.scnView.session.run(configuration)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        self.scnView.session.pause()
    }
    //Partie de création d'écran pour lire des vidéos
    func createVideo(size: CGSize) -> SKScene {
        let skScene = SKScene(size: CGSize(width: 1280, height: 700))
        let player = AVPlayer(url: videoURL)
        //Régler la vidéo pour répéter le réglage
        NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime,
                                               object: player.currentItem, queue: nil) { (_) in
            player.seek(to: CMTime.zero)
            player.play()
        }
        
        let skNode = SKVideoNode(avPlayer: player)
        //Ajuster la position et l'orientation de la vidéo
        skNode.position = CGPoint(x: skScene.size.width / 2.0, y: skScene.size.height / 2.0)
        skNode.size = skScene.size
        skNode.yScale = -1.0
        skNode.play()
        skScene.addChild(skNode)
        
        return skScene
    }
    
    //Delegate Méthode qui détecte un avion et s'enflamme lorsque ARAnchor est placé
    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
        guard let planeAnchor = anchor as? ARPlaneAnchor else {
            return
        }
        DispatchQueue.main.async {
            //Créez un avion qui sera l'écran pour lire la vidéo
            let plane = SCNPlane(width: CGFloat(planeAnchor.extent.x), height: CGFloat(planeAnchor.extent.z))
            let planeNode = SCNNode(geometry: plane)
            //Ajuster la position et l'orientation du plan
            planeNode.position = SCNVector3(x: planeAnchor.center.x,
                                            y: planeAnchor.center.y,
                                            z: planeAnchor.center.z)
            planeNode.eulerAngles.x = -.pi / 2
            node.addChildNode(planeNode)
        }
    }
    
    //Déléguer la méthode qui se déclenche lorsqu'une ancre AR existante est mise à jour
    func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
        guard let planeAnchor = anchor as? ARPlaneAnchor,
              let plane = node.childNodes.first?.geometry as? SCNPlane else {
            return
        }
        //Branche selon que la taille de l'avion est de 20 cm x 20 cm ou plus Cette condition est gratuite.
        if plane.height > 0.2 && plane.width > 0.2 {
            //Si la vidéo est déjà collée dans l'avion, quittez le processus
            if plane.materials.first?.diffuse.contents is SKScene {
                return
            }
            let size = CGSize(width: plane.width, height: plane.height)
            let skScene = self.createVideo(size: size)
            let material = SCNMaterial()
            material.diffuse.contents = skScene
            plane.materials = [material]
        }else {
            plane.width = CGFloat(planeAnchor.extent.x)
            plane.height = CGFloat(planeAnchor.extent.z)
        }
    }
}

Commentaire individuel

self.videoURL = Bundle.main.url(forResource: "pien", withExtension: "mp4")!

let player = AVPlayer(url: videoURL)

Tout d'abord, concernant le chargement des vidéos, l'URL est viewDidLoad () et AVPlayer est obtenu par une méthode appelée createVideo (). Vous pouvez obtenir AVPlayer avec le même viewDidLoad () que l'URL et le laisser comme variable membre, mais dans ce cas, toutes les vidéos lues sur chaque écran seront les mêmes.

let plane = SCNPlane(width: CGFloat(planeAnchor.extent.x), height: CGFloat(planeAnchor.extent.z))
let planeNode = SCNNode(geometry: plane)
planeNode.position = SCNVector3(x: planeAnchor.center.x,
                                y: planeAnchor.center.y,
                                z: planeAnchor.center.z)
planeNode.eulerAngles.x = -.pi / 2

La partie qui crée le plan qui sera l'écran suivant. Vous devez faire attention à ce que la hauteur d'argument de SCNPlane soit spécifiée comme extend.z d'ARPlaneAnchor. ARPlaneAnchor a une profondeur d'axe y, donc si vous spécifiez extend.y comme argument, il ne sera pas affiché. De plus, l'orientation eulerAngles.x du planeNode créé est également perpendiculaire au plan détecté par défaut, il est donc nécessaire de la modifier pour qu'elle recouvre le plan.

if plane.height > 0.2 && plane.width > 0.2 {
    if plane.materials.first?.diffuse.contents is SKScene {
        return
    }
    let skScene = self.createVideo()
    let material = SCNMaterial()
    material.diffuse.contents = skScene
    plane.materials = [material]
}else {
    plane.width = CGFloat(planeAnchor.extent.x)
    plane.height = CGFloat(planeAnchor.extent.z)
}

Enfin, c'est la partie pour coller la vidéo sur SCN Plane. Cette fois, je vérifie si la hauteur et la largeur du plan sont au-dessus d'une certaine valeur avec l'expression conditionnelle, mais c'est parce que si la condition n'est pas définie, la vidéo sera collée à ce stade si l'ARPlaneAnchor est mis à jour même un peu. est. Vous pouvez mettre à jour la hauteur et la largeur même après avoir collé la vidéo, mais chaque fois que vous modifiez la taille de la vidéo et la collez à nouveau, la vidéo sera également lue depuis le début. Les conditions telles que la hauteur et la largeur peuvent être modifiées librement. Si l'expression conditionnelle est True, l'expression conditionnelle réapparaîtra, mais cela vous empêchera de coller à nouveau la vidéo si vous l'avez déjà collée.

Si l'expression conditionnelle est False, la taille d'ARPlaneAnchor mise à jour est appliquée au SCNPlane existant. Veuillez noter que cela ne sera pas affiché si extend.y est spécifié, comme dans la pièce où le plan a été créé.

Sommaire

Le résultat est comme indiqué au début. J'ai pu détecter l'avion et lire la vidéo sur plusieurs écrans. Une seule vidéo a été lue cette fois, mais je pense que vous pouvez lire plusieurs types de vidéos sur chaque écran en modifiant les conditions. Merci d'avoir lu jusqu'ici.

Recommended Posts

[Swift, ARKit] Lire la vidéo sur plusieurs écrans à l'aide des avions détectés