web-dev-qa-db-fra.com

ARKit - Obtenir la position actuelle d'ARCamera dans une scène

J'apprends à la fois ARKit et Scenekit simultanément, et le défi a été difficile.

Avec la création d'une session ARWorldTrackingSessionConfiguration, je me demandais si quelqu'un connaissait un moyen d'obtenir la position de la "caméra" de l'utilisateur dans la session de la scène. L'idée est que je veux animer un objet vers la position actuelle de l'utilisateur.

let reaperScene = SCNScene(named: "reaper.dae")!
let reaperNode = reaperScene.rootNode.childNode(withName: "reaper", recursively: true)!
reaperNode.position = SCNVector3Make(0, 0, -1)
let scene = SCNScene()
scene.rootNode.addChildNode(reaperNode)

// some unknown amount of time later   
let currentCameraPosition = sceneView.pointOfView?.position
let moveAction = SCNAction.move(to: currentCameraPosition!, duration: 1.0)
reaperNode.runAction(moveAction)

Cependant, il semble que currentCameraPosition soit toujours [0,0,0], même si je déplace la caméra. Une idée de ce que je fais mal? Finalement, l’idée est de faire pivoter l’objet autour d’une sphère invisible jusqu’à ce qu’il se trouve devant la caméra, puis de l’animer, en effectuant une opération semblable à celle-ci: le nœud Rotation SCNCamera regarde un objet autour d’une sphère imaginaire = (de cette façon, l'utilisateur voit l'objet s'animer vers lui)

Merci pour toute aide.

28
Ryan Pfister

Définissez-vous comme le ARSession.delegate. Ensuite, vous pouvez implémenter session(_:didUpdate:) qui vous donnera un ARFrame pour chaque image traitée dans votre session. Le cadre a une propriété camera qui contient des informations sur la transformation, la rotation et la position des caméras.

func session(_ session: ARSession, didUpdate frame: ARFrame) {
    // Do something with the new transform
    let currentTransform = frame.camera.transform
    doSomething(with: currentTransform)
}

Comme rickster a souligné que vous pouvez toujours obtenir le ARFrame actuel et la position de la caméra à travers lui en appelant session.currentFrame. Ceci est utile si vous avez besoin de la position une seule fois, par exemple pour déplacer un noeud à l'emplacement de la caméra, mais vous devez utiliser la méthode delegate si vous souhaitez obtenir des mises à jour de la position de la caméra.

23
jlsiewert

Je sais qu'il a été résolu, mais j'ai une petite solution soignée pour cela .. Je préférerais ajouter une méthode de rendu du délégué .. c'est une méthode dans ARSCNViewDelegate

func renderer(_ renderer: SCNSceneRenderer, willRenderScene scene: SCNScene, atTime time: TimeInterval) {
    guard let pointOfView = sceneView.pointOfView else { return }
    let transform = pointOfView.transform
    let orientation = SCNVector3(-transform.m31, -transform.m32, transform.m33)
    let location = SCNVector3(transform.m41, transform.m42, transform.m43)
    let currentPositionOfCamera = orientation + location
    print(currentPositionOfCamera)
}

bien sûr, vous ne pouvez pas ajouter les deux SCNVector3 par défaut .. vous devez donc coller hors de la classe les éléments suivants

func +(lhv:SCNVector3, rhv:SCNVector3) -> SCNVector3 {
     return SCNVector3(lhv.x + rhv.x, lhv.y + rhv.y, lhv.z + rhv.z)
}
13
Mohamed Emad Hegab

Pour votre commodité, vous pouvez créer une extension ViewController avec une méthode d'instance session(_:didUpdate:). Voici le code:

extension ViewController: ARSessionDelegate {

    func session(_ session: ARSession, didUpdate frame: ARFrame) {
        let transform = currentFrame.camera.transform 
        print("Updates")                               // UPDATING        
    }
}

class ViewController: UIViewController, ARSCNViewDelegate {

    @IBOutlet var sceneView: ARSCNView!

    override func viewDidLoad() {
        super.viewDidLoad()
        sceneView.delegate = self                     // ARVIEW DELEGATE
    }   
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        let configuration = ARWorldTrackingConfiguration()
        sceneView.session.run(configuration)
        sceneView.session.delegate = self             // ARSESSION DELEGATE
    }
}
2
ARGeo