【问题标题】:How to place an AR object on plane WITHOUT ARHitTest?如何在没有 ARHitTest 的情况下将 AR 对象放置在平面上?
【发布时间】:2020-08-19 19:59:02
【问题描述】:

我正在开发一个 AR 项目并尝试将对象添加到水平平面。我的目的是让用户在他们的环境中搜索对象,一旦检测到水平面,对象就会出现在平面的中心点上。代码如下:

    func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
        
        if anchor is ARPlaneAnchor {
            
            guard let planeAnchor = anchor as? ARPlaneAnchor else { return }
            
            let plane = SCNPlane(width: CGFloat(planeAnchor.extent.x), height: CGFloat(planeAnchor.extent.z))
            let planeNode = SCNNode()
            planeNode.position = SCNVector3(x: planeAnchor.center.x, y: 0, z: planeAnchor.center.z)
            planeNode.geometry = plane
            print("Plane Node: \(planeNode.position)")
            planeNode.transform = SCNMatrix4MakeRotation(-Float.pi / 2, 1, 0, 0)
            node.addChildNode(planeNode)
            
            let chestScene = SCNScene(named: "art.scnassets/empty_treasure_chest copy.scn")
            
            guard let chestNode = chestScene?.rootNode.childNode(withName: "chest", recursively: true) else { return }
            
            sceneView.scene.rootNode.addChildNode(chestNode)
            chestNode.position = planeNode.position
            print("Chest Node: \(chestNode.position)")
            
            sceneView.scene.rootNode.enumerateChildNodes { (node, _) in
                
                if node.name == "chest_lid_top_wood"  {
                    
                    print("found top")
                    top = node
                    top.physicsBody = SCNPhysicsBody(type: .static, shape: SCNPhysicsShape(node: top, options: nil))
                    
                    
                } else if node.name == "chest_bottom_wood" {
                    
                    print("found bottom")
                    bottom = node
                    bottom.physicsBody = SCNPhysicsBody(type: .static, shape: SCNPhysicsShape(node: bottom, options: nil))
                    
                }
            }
        } else {
            return
        }
        
    }

应用程序将正确检测平面,但对象不会直接放置在平面上,通常它会在世界原点位置抬离平面。更令人困惑的是,我有打印语句显示 planeNode 和 chestNode 的位置,尽管我将 chestNode 的位置分配给 planeNode 位置,但这些值最终是不同的。我知道大多数人使用 ARHitTest 来放置 AR 对象,但这样做会阻碍我试图实现的用户体验。

有什么建议吗?提前致谢!

干杯!

【问题讨论】:

  • 为什么将planeNode.positiony 值设置为0?也许应该改成planeNode.position = SCNVector3(x: planeAnchor.center.x, y: planeAnchor.center.y, z: planeAnchor.center.z)
  • @bluepanda 因为我的意图是不让飞机升空。我尝试将 planeNode.position.y 更改为 planeAnchor.center.y 以进行踢腿和咯咯笑,但没有效果。我实际上已经决定改变方法并使用 RealityKit 而不是 SceneKit。通过这样做,我能够以更少的头痛实现我正在寻找的功能????

标签: swift xcode arkit


【解决方案1】:

根据我的经验,ARKit 在计算节点的worldPosition 之前将委托方法称为“提前”。它仍然是[0, 0, 0],这就是为什么你的对象会出现在世界原点。

有两种解决方法:

您可以将您的chestNode 添加为node 的子代,而不是scnene 的rootNode。 但是,这将导致节点在每次ARKit 更新平面时移动,因为这会更新node 的位置。这通常是您想要的。

另一种方法是在更新chestNode 的位置之前等待至少 1 帧,方法是将节点的实际位置包装在类似的东西中

DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) { [weak sceneView] in 
      sceneView?.scene.rootNode.addChildNode(chestNode)
      chestNode.position = planeNode.position
}

【讨论】:

  • 好的,我明白了。为了知识,我将不得不尝试这些。与此同时,虽然我实际上已经决定改变方法并使用 RealityKit 而不是 SceneKit。通过这样做,我能够更简单地实现我正在寻找的功能。此外,平面检测加载速度更快。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-31
  • 2019-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-29
相关资源
最近更新 更多