首页 文章

如何保持ARKit SCNNode到位

提问于
浏览
18

嘿,我想弄清楚 . 如何保持一个简单的节点 . 当我在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) {
 }

Or 最有可能是位置设置

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

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

1 回答

  • 22

    可能会发生两种“四处走动” .


    一个是ARKit不断改进其设备's position in the real world maps to the abstract coordinate space you'如何放置虚拟内容的估计 . 例如,假设您将虚拟对象放在 (0, 0, -0.5) ,然后将设备向左移动10厘米 . 仅当ARKit精确跟踪移动时,虚拟对象才会显示为锚定在物理空间中 . 但是视觉惯性测距并不是ARKit认为你向左移动10.5厘米的可能性 - 在这种情况下,即使它在ARKit / SceneKit坐标空间中的位置,你的虚拟物体也会向右显示5毫米"slip" .

    除了希望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:) 中收到的节点),则为'll stay attached to the plane as ARKit refines its estimate of the plane'的位置 . 您最初会获得更多的移动,但是作为平面检测"settles",您的虚拟对象将减少 .

    (当你使节点成为飞机的子节点时,你不需要设置它的位置 - 零位意味着它就在飞机所在的位置 . 无论什么,你需要相对于飞机设置它的位置 - 即它上面/下面/沿着它走多远 . )

相关问题