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, глядя на объект вокруг воображаемой сферы (таким образом, что пользователь видит объект оживить к ним)
Спасибо за любую помощь.
Ответы
Ответ 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
}
}