Я следовал этому коду от @rickster, который работает на 100% и выглядит отлично . В видео он анимирует SCNNode, который устанавливается с помощью ARAnchor из одной позиции в другую и обратно. Я пытался сделать что-то подобное, за исключением того, что я хочу, чтобы узел, установленный с помощью ARAnchor, следовал / обновлял свою позицию для другого узла, который является дочерним элементом камеры.
У меня проблема с обновлением позиции в func renderer(_ renderer: SCNSceneRenderer, willRenderScene scene: SCNScene, atTime time: TimeInterval) { }
Я пытался анимировать узел, для которого установлен ARAnchor, чтобы следовать за другим узлом, но он не работает, он следует назад и в обратном направлении:
let animation = CABasicAnimation(keyPath: #keyPath(SCNNode.transform))
animation.fromValue = nodeSetWithARAnchor.transform
animation.toValue = nodeTiedToCamera.transform
animation.duration = 1
nodeSetWithARAnchor.removeAllAnimations()
nodeSetWithARAnchor.addAnimation(animation, forKey: nil)
Затем я попытался удалить ARAnchor и сбросить его узлы .worldPostion
и .simdWorldTransform
, но узлы появляются. Это в шагах 7 и 8 ниже.
Как мне заставить nodeSetWithARAnchor
обновить свой ARAnchor и положение, чтобы всегда следовать nodeTiedToCamera
?
Обновление На шаге 6 теперь, когда я установил nodeSetWithARAnchor SCVector3
для соответствия nodeTiedToCameradWorld's SCVector3
и установил .transform
для соответствия коду анимации nodeTiedToCameradWorldTransform
@ rickster, лучше всего работает, потому что мне не нужно удалять любые якоря. Есть еще одна проблема. nodeSetWithARAnchor
реагирует, когда я перемещаю устройство, но реагирует в обратном и обратном направлениях.
Когда я поднимаю устройство вверх, изображение идет вправо, а когда я выключаю устройство, изображение идет влево. Когда я поворачиваю устройство влево, изображение увеличивается, а когда я поворачиваю устройство вправо, изображение уменьшается. Он следует за изображением, которое я привязал к камере, но неверно.
let configuration = ARWorldTrackingConfiguration()
var nodeSetWithARAnchor: SCNNode?
var nodeTiedToCamera: SCNNode?
var anchors: [ARAnchor] = []
override func viewDidLoad() {
super.viewDidLoad()
configuration.planeDetection = [.horizontal, .vertical]
configuration.maximumNumberOfTrackedImages = 1
// 1. once this anchor is set inside renderer(_:didAdd:for:) I initialize the nodeSetWithARAnchor at 30cm behind the device's camera's initial position
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
var translation = matrix_identity_float4x4
translation.columns.3.z = -0.3
let transform = simd_mul(self.sceneView.session.currentFrame!.camera.transform, translation)
let anchor = ARAnchor(transform: transform)
self.sceneView.session.add(anchor: anchor)
}
// 2. the nodeTiedToCamera will always go where ever the device's camera goes
let plane = SCNPlane(width: 0.1, height: 0.1)
nodeTiedToCamera = SCNNode(geometry: plane)
nodeTiedToCamera!.position = SCNVector3(x: -0.15, y: 0.45, z: -1.25) // I don't want it directly in front of the camera
nodeTiedToCamera!.geometry?.fisrtMaterial?.diffuse.contents = UIColor.red
sceneView.pointOfView.addChildNode(nodeTiedToCamera!)
}
// 3. I init the nodeSetWithARAnchor, add it to the sceneView's root node, and keep a copy of it's anchor
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
DispatchQueue.main.async {
if self.nodeSetWithARAnchor == nil {
// create geometry ...
self.nodeSetWithARAnchor = SCNNode(geometry: geometry)
node.addChildNode(self.nodeSetWithARAnchor!)
}
self.anchors.removeAll()
self.anchors.append(anchor)
}
}
func renderer(_ renderer: SCNSceneRenderer, willRenderScene scene: SCNScene, atTime time: TimeInterval) {
DispatchQueue.main.async {
// 4. get the only child that is tied to the camera which is the nodeTiedToCamera
guard let pointOfView = self.sceneView.pointOfView else { return }
guard let child = pointOfView.childNodes.first else { return }
// 5. get it's .worldPosition && it's .simdWorldTransform
let nodeTiedToCameradWorldPosition = child.worldPosition
let nodeTiedToCameradWorldTransform = child.worldTransform
if let nodeSetWithARAnchor = self.nodeSetWithARAnchor, let anchorToRemove = self.anchors.first {
// 6. set the nodeSetWithARAnchor SCVector3 to match the nodeTiedToCameradWorld's SCVector3 and set its .transform to match the nodeTiedToCameradWorldTransform
nodeSetWithARAnchor.position = nodeTiedToCameradWorldPosition
nodeSetWithARAnchor.transform = nodeTiedToCameradWorldTransform
let animation = CABasicAnimation(keyPath: #keyPath(SCNNode.transform))
animation.fromValue = nodeSetWithARAnchor.transform
animation.toValue = nodeTiedToCamera.transform
animation.duration = 1
nodeSetWithARAnchor.removeAllAnimations()
nodeSetWithARAnchor.addAnimation(animation, forKey: nil)
// 7. remove all ARAnchors
//self.sceneView.session.remove(anchor: anchorToRemove)
//self.anchors.removeAll()
// 8. add a new anchor to the session and set it with the nodeSetWithARAnchor.simdWorldTransform
//let anchor = ARAnchor(transform: nodeSetWithARAnchor.simdWorldTransform)
//self.sceneView.session.add(anchor: anchor)
}
}
}
func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
guard let node = self.nodeSetWithARAnchor else { return }
if let pointOfView = sceneView.pointOfView {
let isVisible = sceneView.isNode(node, insideFrustumOf: pointOfView)
print("Is node visible: \(isVisible)")
}
}