Swift - 如何更新 ARAnchor 以跟随相机的位置 [英] Swift -How to update ARAnchor to follow Camera's position
问题描述
我遵循了@rickster 的此代码,该代码 100% 有效,看起来很棒.在视频中,他正在为 SCNNode 设置动画,该 SCNNode 使用 ARAnchor 从一个位置到另一个位置并返回.我尝试做类似的事情,但我希望使用 ARAnchor 设置的节点跟随/更新它的位置到另一个作为相机子节点的节点.
I followed this code from @rickster which 100% works and looks great. In the video he's animating a SCNNode that is set using an ARAnchor from 1 position to another and back. I tried to do something similar except I want the node that is set with the ARAnchor to follow/update it's position to another node that is a child of the camera.
我在更新 func renderer(_ renderer: SCNSceneRenderer, willRenderScene scene: SCNScene, atTime time: TimeInterval) { }
我尝试为使用 ARAnchor 设置的节点设置动画以跟随另一个节点,但它不起作用,它向后和反向跟随:
I tried to animate the node that is set with the ARAnchor to follow the other node but it's not working, it follows backwards and in reverse:
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 以下.
I then tried to remove the ARAnchor and reset its node's .worldPostion
and .simdWorldTransform
but the node diappears. It's in steps 7 & 8 below.
如何让 nodeSetWithARAnchor
更新其 ARAnchor 和位置以始终跟随 nodeTiedToCamera
?
How can I get the nodeSetWithARAnchor
to update its ARAnchor and position to always follow the nodeTiedToCamera
?
更新 在第 6 步中,我将 nodeSetWithARAnchor SCVector3
设置为匹配 nodeTiedToCameradWorld 的 SCVector3
并设置其 .transform
匹配 nodeTiedToCameradWorldTransform
@rickster 的动画代码效果最好,因为我不必删除任何锚点.但是还有另一个问题.nodeSetWithARAnchor
在我移动设备时响应,但它向后和反向响应.
Update In Step 6 now that I set the nodeSetWithARAnchor SCVector3
to match the nodeTiedToCameradWorld's SCVector3
and set its .transform
to match the nodeTiedToCameradWorldTransform
@rickster's animation code works the best because I don't I have to remove any anchors. There is another problem though. The nodeSetWithARAnchor
responds when I move the device but it responds backwards and in reverse.
当我向上转动设备时,图像向右移动,当我向下转动设备时,图像向左移动.当我向左转动设备时,图像会上升,而当我向右转动设备时,图像会下降.它跟随我绑定到相机的图像,但跟随它不正确.
When I turn the device up the image goes right and when I turn the device down the image goes left. When I turn the device left the image goes up and when I turn the device right the image goes down. It's following the image I have tied to the camera but it's following it incorrectly.
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)")
}
}
推荐答案
这是一整天的事情,但得到了它的工作.我只需要在 renderer(:willRenderScene:atTime:)
中切换 2 行代码,然后按照下面的确切顺序运行它们.我不必删除和添加锚点或运行任何动画代码.
It was an ALL day thing but got it working. I only had to switch around 2 lines of code in renderer(:willRenderScene:atTime:)
and run them in the exact order below. I didn't have to remove and add anchors or run any animation code.
func renderer(_ renderer: SCNSceneRenderer, willRenderScene scene: SCNScene, atTime time: TimeInterval) {
DispatchQueue.main.async { [weak self] in
guard let safeSelf = self else { return }
guard let pointOfView = safeSelf.sceneView.pointOfView else { return }
guard let child = pointOfView.childNodes.first else { return } // child is the nodeTiedToCamera
if let nodeSetWithARAnchor = safeSelf.nodeSetWithARAnchor {
// *** I just had to switch around these 2 lines of code and run them in this exact order ***
nodeSetWithARAnchor.transform = child.worldTransform
nodeSetWithARAnchor.worldPosition = child.worldPosition
}
}
}
这篇关于Swift - 如何更新 ARAnchor 以跟随相机的位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!