37 votes

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

Je suis en train d'apprendre ARKit et Scenekit simultanément, et cela a été un peu un défi.

Après avoir créé 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 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. Avez-vous une idée de ce que je fais de mal ? En fait, l'idée est de faire tourner l'objet autour d'une sphère invisible jusqu'à ce qu'il soit devant la caméra, puis de l'animer en faisant quelque chose de similaire à ceci : Faire pivoter le nœud SCNCamera regardant 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.

28voto

jlsiewert Points 2198

Définissez-vous comme le ARSession.delegate . Ensuite, vous pouvez mettre en œuvre session(_:didUpdate:) qui vous donnera un ARFrame pour chaque image traitée dans votre session. Le cadre a un camera qui contient des informations sur la transformation, la rotation et la position de la caméra.

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 et la position de la caméra à travers elle en appelant session.currentFrame . C'est utile si vous n'avez besoin de la position qu'une seule fois, par exemple pour déplacer un nœud où la caméra s'est trouvée, mais vous devriez utiliser la fonction delegate si vous souhaitez obtenir des mises à jour sur la position de la caméra.

5 votes

Cette méthode fonctionne, mais vous pouvez également obtenir des cadres sans être le délégué de la session en obtenant l'identifiant de la session. currentFrame propriété.

1 votes

@rickster vous êtes serré et j'ai édité la réponse, mais généralement vous voulez que les autres noeuds réagissent à votre changement de position, par exemple en vous suivant. Dans ce cas, vous voudriez de toute façon des mises à jour constantes sur les nouvelles positions de la caméra.

2 votes

C'est vrai. Le fait est que, selon la façon dont votre application est configurée, ARKit peut soit vous fournir des images à 60 fps et effectuer le rendu au fur et à mesure que vous les obtenez, soit exécuter votre propre boucle de rendu à (jusqu'à) 60 fps et demander à ARKit une image chaque fois que vous en avez besoin. Les deux méthodes sont prises en charge, alors utilisez celle qui vous convient le mieux.

13voto

Je sais que le problème a été résolu, mais j'ai une petite solution Je préférerais ajouter une méthode de délégation de rendu 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 ce qui suit à partir de la classe

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

1 votes

Pourquoi prenez-vous simplement les entrées diagonales de la matrice de rotation ? Et pourquoi la "position" est-elle égale à "orientation + emplacement". La position est l'emplacement, c'est-à-dire la dernière colonne de la transformation. La matrice 3x3 supérieure gauche contient l'orientation (et éventuellement l'échelle et le cisaillement). Il existe différentes méthodes pour en extraire le tangage, le lacet et le roulis, mais la diagonale n'en fait pas partie.

0 votes

@kjyv où avez-vous vu l'emplacement est la dernière colonne de la transformée ? merci de partager !

0 votes

La matrice de transformation est une matrice 4x4, d'où des coordonnées homogènes. La documentation ne le dit peut-être pas explicitement mais c'est plutôt standard. Regardez, par exemple, ici pour le cas 2D. fr.wikipedia.org/wiki/

7voto

Gigantic Points 4447

Pour votre commodité, vous pouvez créer un ViewController avec une méthode d'instance session(_:didUpdate:) où une mise à jour sera effectuée.

Voici le code :

extension ViewController: ARSessionDelegate {

    func session(_ session: ARSession, didUpdate frame: ARFrame) {
        let transform = frame.camera.transform
        let position = transform.columns.3
        print(position.x, position.y, position.z)     // 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
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X