Подтвердить что ты не робот

ARKit - Получить текущую позицию ARCamera в сцене

Я нахожусь в процессе изучения ARKit и Scenekit одновременно, и это было немного сложной задачей.

С созданным сеансом ARWorldTrackingSessionConfiguration мне было интересно, знает ли кто-нибудь, как определить положение пользовательской "камеры" в сеансе сцены. Идея в том, что я хочу анимировать объект в направлении текущей позиции пользователя.

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)

Тем не менее, кажется, что currentCameraPosition всегда [0,0,0], хотя я перемещаю камеру. Есть идеи, что я делаю не так? В конце концов идея заключается в том, чтобы я вращал объект вокруг невидимой сферы, пока он не оказался перед камерой, а затем анимировал его, выполняя что-то похожее на это: вращал узел SCNCamera, глядя на объект вокруг воображаемой сферы (таким образом, что пользователь видит объект оживить к ним)

Спасибо за любую помощь.

4b9b3361

Ответ 1

Установите себя в качестве ARSession.delegate. Чем вы можете реализовать session(_:didUpdate:) который даст вам ARFrame для каждого кадра, обработанного в вашем сеансе. Кадр имеет свойство camera которое содержит информацию о преобразовании, повороте и положении камер.

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

Как указал Рикстер, вы всегда можете получить текущий ARFrame и положение камеры через него, вызвав session.currentFrame. Это полезно, если вам нужна позиция только один раз, например, чтобы переместить узел, где находилась камера, но вы должны использовать метод delegate если вы хотите получать обновления о положении камеры.

Ответ 2

Я знаю, что это было решено, но у меня есть небольшое опрятное решение. Я бы предпочел добавить метод делегата рендеринга. Это метод в 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)
}

конечно, вы не можете по умолчанию добавить два SCNVector3 из коробки. Поэтому вам нужно вставить из класса следующие

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

Ответ 3

Для вашего удобства вы можете создать расширение ViewController с session(_:didUpdate:) метода экземпляра session(_:didUpdate:). Вот код:

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
    }
}