我跟随这段代码从@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 nodeTiedToCamera**?** 更新其ARAnchor和位置以始终遵循
在步骤6中,Update设置了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)")
}
}发布于 2020-02-21 09:46:07
这是一个整天的事情,但让它发挥作用。我只需在renderer(:willRenderScene:atTime:)中切换大约2行代码,并按照下面的确切顺序运行它们。我不需要删除和添加锚或运行任何动画代码。
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
}
}
}https://stackoverflow.com/questions/60327523
复制相似问题