35

我正在同时学习 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],即使我正在移动相机。知道我做错了什么吗?最终的想法是我将围绕一个不可见的球体旋转对象,直到它位于相机前面,然后对其进行动画处理,执行类似于此的操作:Rotate SCNCamera 节点查看一个假想球体周围的对象(用户看到的方式对象向他们移动)

谢谢你的帮助。

4

3 回答 3

28

将自己设置为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)
}

正如rickster指出的那样,您始终可以ARFrame通过调用session.currentFrame. 如果您只需要一次位置,这很有用,例如移动相机所在的节点,但delegate如果您想获取相机位置的更新,您应该使用该方法。

于 2017-07-13T19:14:32.237 回答
14

我知道它已经解决了,但我有一个简洁的解决方案。我更喜欢添加一个渲染器委托方法。它是 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)
}
于 2017-11-11T19:28:10.197 回答
6

为方便起见,您可以ViewController使用实例方法创建扩展,session(_:didUpdate:)其中将发生更新。

这是代码:

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
    }
}
于 2019-04-22T16:22:22.487 回答