如何保持ARKit SCNNode到位

时间:2017-07-10 19:30:34

标签: ios swift arkit

嘿,我想弄清楚。如何保持一个简单的节点。当我在ARKit中走动时

代码:

 func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {

    if let planeAnchor = anchor as? ARPlaneAnchor {

    if planeDetected == false { // Bool only allows 1 plane to be added
            planeDetected = true
        self.addPlane(node: node, anchor: planeAnchor)
    }

    }
}

这会添加SCNNode

    func addPlane(node: SCNNode, anchor: ARPlaneAnchor) {

    // We add the anchor plane here

    let showDebugVisuals = Bool()
    let plane = Plane(anchor, showDebugVisuals)
    planes[anchor] = plane
    node.addChildNode(plane)



    // We add our custom SCNNode here 

    let scene = SCNScene(named: "art.scnassets/PlayerModel.scn")!
    let Body = scene.rootNode.childNode(withName: "Body", recursively: true)!

    Body.position = SCNVector3.positionFromTransform(anchor.transform)
    Body.movabilityHint = .movable
    wrapperNode.position = SCNVector3.positionFromTransform(anchor.transform)

    wrapperNode.addChildNode(Body)

    scnView.scene.rootNode.addChildNode(wrapperNode)

我试过添加一个Plane / Anchor Node并将“Body”节点放在那里,但它仍在移动。我想也许它与更新功能有关。

 func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {
 }

最有可能是位置设置

wrapperNode.position = SCNVector3.positionFromTransform(anchor.transform)

我浏览了互联网上的每个源/项目文件/视频,没有人能够解决这个简单的问题。

2 个答案:

答案 0 :(得分:26)

这里可能会发生两种“四处走动”。

一个是ARKit不断改进其对现实世界中设备位置如何映射到您放置虚拟内容的抽象坐标空间的估计。例如,假设您将虚拟对象放在(0, 0, -0.5) ,然后将设备向左移动10厘米。仅当ARKit精确跟踪移动时,虚拟对象才会显示为锚定在物理空间中。但是视觉惯性测距不是一门精确的科学,所以ARKit可能认为你向左移动了10.5厘米 - 在这种情况下,你的虚拟物体看起来会向右滑动5毫米,即使它在ARKit / SceneKit坐标空间中的位置。

除了希望Apple使设备具有更好的传感器,更好的相机或更好的CPU / GPU以及改进世界跟踪科学之外,你无法真正做到这一点。 (在充足的时间里,这可能是一个安全的赌注,尽管这可能对您当前的项目没有帮助。)

既然你也正在处理飞机检测,那还有另一个问题。 ARKit不断完善其对检测到的飞机所在位置的估算。因此,即使平面的真实位置没有改变,它在ARKit / SceneKit坐标空间中的位置也是。

这种运动通常是一件好事 - 如果您希望虚拟对象看起来固定在真实世界的表面上,您需要确定该表面的位置。你可以看到一些运动,因为平面检测可以更加确定表面的位置,但是在很短的时间之后,当你将相机移动到计划锚定的虚拟对象时,你应该看到更少的“滑动”而不是那些只漂浮在世界中的虚拟对象空间。

在你的代码中,你没有利用平面检测来使你的自定义内容(来自“PlayerModel.scn”)坚持飞机锚:

wrapperNode.position = SCNVector3.positionFromTransform(anchor.transform)
wrapperNode.addChildNode(Body)
scnView.scene.rootNode.addChildNode(wrapperNode)

此代码使用平面锚点的初始位置将wrapperNode定位在世界空间中(因为您将其作为根节点的子节点)。如果你让wrapperNode成为飞机锚点节点(你在renderer(_:didAdd:for:)中收到的节点)的子节点,它将保持与飞机的连接,因为ARKit会精确估计飞机的位置。你最初会得到更多的动作,但随着平面检测“稳定”,你的虚拟物体将“减少”。

(当你使节点成为飞机的子节点时,你不需要设置它的位置 - 零位意味着它就在飞机所在的位置。任何东西,你需要设置它的位置只相对于飞机 - 即它上/下/沿它多远。)

答案 1 :(得分:0)

要保持SCNNode到位,您可以在获得所需结果后禁用SceneView平面检测。

let configuration = ARWorldTrackingConfiguration(); configuration.planeDetection = [] self.sceneView.session.run(configuration)

其原因是ARKit不断重新估计检测到的平面的位置,从而导致SCNNode移动。