Swift-如何更新ARAnchor以跟随相机的位置 [英] Swift -How to update ARAnchor to follow Camera's position

查看:107
本文介绍了Swift-如何更新ARAnchor以跟随相机的位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遵循了@rickster的此代码,其中100%有效,并且

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步和第9步.下方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's 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:)中切换两行代码,并按照下面的确切顺序运行它们.我不必删除和添加锚点或运行任何动画代码.

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 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆