首页 > 解决方案 > 如何在没有 ARHitTest 的情况下将 AR 对象放置在平面上?

问题描述

我正在做一个 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 对象,但这样做会阻碍我试图实现的用户体验。

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

干杯!

标签: swiftxcodearkit

解决方案


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

有两种解决方法:

您可以将您的添加chestNode为孩子node而不是场景的rootNode. 但是,这会导致每次ARKit更新平面时节点都会移动,因为这会更新node. 这通常是你想要的。

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

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

推荐阅读