ARKit SKVideoNode Jugando en Render

Problema principal

Añado esta sección DESPUÉS para aclarar el problema. - Puedo pausar mi video (no quiero que se reproduzca en bucle). Cuando mi nodo aparece, mi nodo reproduce mi video, incluso si está en pausa. Si mi video ha terminado de reproducirse y aparece, se reiniciará. Quiero ELIMINAR este comportamiento.

En mi aplicación, tengo unSKVideoNode creado a partir de unaAVPlayer(:URL) dentro del espacio 3D usandoSCNNode objetos ySCNGeometry objetos. Yo sueloARKit .ImageTracking para determinar cuándo se encuentra una imagen específica y reproducir un video desde allí. Todo es bueno y elegante, excepto que el jugador determina jugar en su propio tiempo, cada vez que aparece AVPlayer; sin embargo, podría ser cuando elARImageAnchor elSCNNode se adjunta a aparece a la vista. De cualquier manera, laAVPlayer se reproduce cada vez que el nodo ve la lente de la cámara. Yo suel

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if(keyPath == "rate") {
        print((object as! AVPlayer).rate)
    }
}

para imprimir la tasa, y es 1, sin embargo, era 0.

Imprimí algún tipo de función de impresiónprint("Play") para todas mis funciones que utilizan player.pause () o player.play () y ninguna de ellas se llama cada vez que se cambia la tasa anterior. ¿Cómo puedo encontrar la fuente de lo que está cambiando la velocidad de mi reproductor?

Revisé el rootnode original,self.sceneview.scene.rootNode.childNodes para asegurarse de que no estoy creando VideoNodes / SCNNodes / AVPlayers adicionales, etc., y parece que solo hay 1.

¿Alguna idea de por qué el SKVideoNode / AVPlayer se está reproduciendo cuando el SCNNode aparece a la vista de la cámara con ARKit? ¡Gracias por adelantado

Edit1:

Hizo una solución alternativa para determinar SOLO cuándo un usuario hizo clic en este nodo

let tap = UITapGestureRecognizer(target: self, action: #selector(self!.tapGesture))
tap.delegate = self!
tap.name = "MyTap"
self!.sceneView.addGestureRecognizer(tap)

y luego dentro de esta próxima función, pongo

@objc func tapGesture(_ gesture:UITapGestureRecognizer) {
    let tappedNodes = self.sceneView.hitTest(gesture.location(in: gesture.view), options: [SCNHitTestOption.searchMode: 1])

    if !tappedNodes.isEmpty {
        for nodes in tappedNodes {
            if nodes.node == videoPlayer3D {
                videoPlayer3D.tappedVideoPlayer = true
                videoPlayer3D.playOrPause()
                break
            }
        }
    }
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if(keyPath == "rate") {
        print((object as! AVPlayer).rate)
        if(!self.tappedVideoPlayer) {
            self.player.pause() //HERE
        }
    }
}

where videoPlayer3D es elSCNNode que contiene el SKVideoNode.

Sin embargo, me sale el errorcom.apple.scenekit.scnview-renderer (17): EXC_BAD_ACCESS (code=2, address=0x16d8f7ad0) en la sección etiquetada "AQUÍ" arriba. Parece que el renderizador de la vista de escena está intentando alterar mi nodo de video en la función de renderizado, aunque ni siquiera uso larenderer(updateAtTime:)unción @, solo uso

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

    guard let imageAnchor = anchor as? ARImageAnchor else { return }

    createVideoNode(imageAnchor)

}

para determinar cuándo veo una imagen, es decir,imageTracking y creo el nodo. ¿Algun consejo

Pensamiento 1

El error se presenta indicando que se está llamando a algún método desde un objeto SCNView para el procesador de métodos (eso es lo que entiendo por el error), pero no tengo el nodo llamado específicamente. Creo que tal vez se está llamando a una acción predeterminada, ya que el nodo se está viendo, sin embargo, no estoy 100% seguro de cómo acceder o determinar qué método. Los objetos que estoy usando no son objetos SCNView, y no creo que hereden de los objetos SCNView (mira el primer párrafo para ver las variables utilizadas). Solo busco eliminar la "acción" del nodo que se reproduce cada vez que está a la vista.

ADICIÓN

En aras de seguir la creación de mi reproductor de video si está interesado, aquí está. Avíseme si hay algo más que le gustaría ver (no estoy seguro de qué más le gustaría ver) y gracias por su ayuda.

func createVideoNode(_ anchor:ARImageAnchor, initialPOV:SCNNode) -> My3DPlayer? {

    guard let currentFrame = self.sceneView.session.currentFrame else {
        return nil
    }

    let delegate = UIApplication.shared.delegate as! AppDelegate

    var videoPlayer:My3DPlayer!
    videoPlayer = delegate.testing ? My3DPlayer(data: nil, currentFrame: currentFrame, anchor: anchor) : My3DPlayer(data: self.urlData, currentFrame: currentFrame, anchor: anchor)

    //Create TapGesture
    let tap = UITapGestureRecognizer(target: self, action: #selector(self.tapGesture))
    tap.delegate = self
    tap.name = "MyTap"
    self.sceneView.addGestureRecognizer(tap)

    return videoPlayer
}

Clase My3dPlayer:

class My3DPlayer: SCNNode {

    init(geometry: SCNGeometry?) {
        super.init()
        self.geometry = geometry
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    convenience init(data:Data?, currentFrame:ARFrame, anchor:ARImageAnchor) {
        self.init(geometry: nil)
        self.createPlayer(currentFrame, data, anchor)
    }

    private func createPlayer(_ frame:ARFrame, _ data:Data?,_ anchor:ARImageAnchor) {

        let physicalSize = anchor.referenceImage.physicalSize

        print("Init Player W/ physicalSize: \(physicalSize)")

        //Create video
        if((UIApplication.shared.delegate! as! AppDelegate).testing) {
            let path = Bundle.main.path(forResource: "Bear", ofType: "mov")
            self.url = URL(fileURLWithPath: path!)
        }
        else {
            let url = data!.getAVAssetURL(location: "MyLocation")
            self.url = url
        }
        let asset = AVAsset(url: self.url)
        let track = asset.tracks(withMediaType: AVMediaType.video).first!
        let playerItem = AVPlayerItem(asset: asset)
        let player = AVPlayer(playerItem: playerItem)
        self.player = player
        var videoSize = track.naturalSize.applying(track.preferredTransform)

        videoSize = CGSize(width: abs(videoSize.width), height: abs(videoSize.height))
        print("Init Video W/ size: \(videoSize)")

        //Determine if landscape or portrait
        self.landscape = videoSize.width > videoSize.height
        print(self.landscape == true ? "Landscape" : "Portrait")

        //Do something when video ended
        NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying(note:)), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)

        //Add observer to determine when Player is ready
        player.addObserver(self, forKeyPath: "status", options: [], context: nil)

        //Create video Node
        let videoNode = SKVideoNode(avPlayer: player)

        //Create 2d scene to put 2d player on - SKScene
        videoNode.position = CGPoint(x: videoSize.width/2, y: videoSize.height/2)
        videoNode.size = videoSize


        //Portrait -- //Landscape doesn't need adjustments??
        if(!self.landscape) {
            let width = videoNode.size.width
            videoNode.size.width = videoNode.size.height
            videoNode.size.height = width
            videoNode.position = CGPoint(x: videoNode.size.width/2, y: videoNode.size.height/2)
        }

        let scene = SKScene(size: videoNode.size)

        //Add videoNode to scene
        scene.addChild(videoNode)

        //Create Button-look even though we don't use the button. Just creates the illusion to pressing play and pause
        let image = UIImage(named: "PlayButton")!
        let texture = SKTexture(image: image)
        self.button = SKSpriteNode(texture: texture)
        self.button.position = videoNode.position

        //Makes the button look like a square
        let minimumSize = [videoSize.width, videoSize.height].min()!
        self.button.size = CGSize(width: minimumSize/4, height: minimumSize/4)
        scene.addChild(button)

        //Get ratio difference from physicalsize and video size
        let widthRatio = Float(physicalSize.width)/Float(videoSize.width)
        let heightRatio = Float(physicalSize.height)/Float(videoSize.height)

        let finalRatio = [widthRatio, heightRatio].min()!

        //Create a Plane (SCNPlane) to put the SKScene on
        let plane = SCNPlane(width: scene.size.width, height: scene.size.height)
        plane.firstMaterial?.diffuse.contents = scene
        plane.firstMaterial?.isDoubleSided = true

        //Set Self.geometry = plane
        self.geometry = plane

        //Size the node correctly
        //Find the real scaling variable
        let scale = CGFloat(finalRatio)
        let appearanceAction = SCNAction.scale(to: scale, duration: 0.4)
        appearanceAction.timingMode = .easeOut

        //Set initial scale to 0 then use action to scale up
        self.scale = SCNVector3Make(0, 0, 0)
        self.runAction(appearanceAction)
    }

    @objc func playerDidFinishPlaying(note: Notification) {
        self.player.seek(to: .zero, toleranceBefore: .zero, toleranceAfter: .zero)
        self.player.seek(to: .zero, toleranceBefore: .zero, toleranceAfter: .zero)
        self.setButtonAlpha(alpha: 1)
    }
}

Esfuerzos1:

He intentado detener el seguimiento a través de:

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

    guard let imageAnchor = anchor as? ARImageAnchor else { return }

    createVideoNode(imageAnchor)
    self.resetConfiguration(turnOnConfig: true, turnOnImageTracking: false)   
}

func resetConfiguration(turnOnConfig: Bool = true, turnOnImageTracking:Bool = false) {
    let configuration = ARWorldTrackingConfiguration()
    if(turnOnImageTracking) {
        guard let referenceImages = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil) else {
            fatalError("Missing expected asset catalog resources.")
        }
        configuration.planeDetection = .horizontal
        configuration.detectionImages = referenceImages
    }
    else {
        configuration.planeDetection = []
    }
    if(turnOnConfig) {
        sceneView.session.run(configuration, options: [.resetTracking])
    }
}

Arriba, he intentado restablecer la configuración. Esto solo hace que restablezca los planos, ya que el video todavía se está reproduciendo en el render. Ya sea que esté en pausa o terminado, se reiniciará y comenzará de nuevo o continuará jugando donde se dejó.

Esfuerzos2:

Yo he tratad

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

    guard let imageAnchor = anchor as? ARImageAnchor else { return }

    createVideoNode(imageAnchor)
    self.pauseTracking()  
}

func pauseTracking() {
    self.sceneView.session.pause()
}

Esto detiene todo, por lo tanto, la cámara incluso se congela ya que no se está rastreando nada. Es completamente inútil aquí.

Respuestas a la pregunta(1)

Su respuesta a la pregunta