ARKit - 使用raycastQuery而非已弃用的hitTest来点击节点

11
在iOS 14中,已经弃用了hitTest(_:types:)。现在似乎应该使用raycastQuery(from:allowing:alignment:)。从文档中得知:

射线投射是找到真实环境表面位置的首选方法,但命中测试功能仍然存在以保持兼容性。使用跟踪的射线投射,ARKit将继续优化结果以提高使用射线放置的虚拟内容的位置精度。

如何使用射线投射进行命中测试SCNNode?

然而,我怎么使用射线投射来命中测试SCNNode?我只看到可以对平面进行命中测试的选项。

raycastQuery方法文档 allowing:的选择仅限平面
Screenshot of documentation for the "raycastQuery(from:allowing:alignment:)" method Screenshot of documentation of the possible options for the "allowing:" argument label, showing 3 different types of planes

这是我的当前代码,它使用命中测试来检测对立方体节点的点击并将其变为蓝色。

class ViewController: UIViewController {

    @IBOutlet weak var sceneView: ARSCNView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        /// Run the configuration
        let worldTrackingConfiguration = ARWorldTrackingConfiguration()
        sceneView.session.run(worldTrackingConfiguration)
        
        /// Make the red cube
        let cube = SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0)
        cube.materials.first?.diffuse.contents = UIColor.red
        
        let cubeNode = SCNNode(geometry: cube)
        cubeNode.position = SCNVector3(0, 0, -0.2) /// 20 cm in front of the camera
        cubeNode.name = "ColorCube"
        
        /// Add the node to the ARKit scene
        sceneView.scene.rootNode.addChildNode(cubeNode)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesBegan(touches, with: event)
        guard let location = touches.first?.location(in: sceneView) else { return }
        
        let results = sceneView.hitTest(location, options: [SCNHitTestOption.searchMode : 1])
        for result in results.filter( { $0.node.name == "ColorCube" }) {  /// See if the beam hit the cube
            let cubeNode = result.node
            cubeNode.geometry?.firstMaterial?.diffuse.contents = UIColor.blue /// change to blue
        }
    }
}

我该如何用等效的raycastQuery代码替换let results = sceneView.hitTest(location, options: [SCNHitTestOption.searchMode : 1])

代码结果的GIF。 点击红色立方体会将其变为蓝色。
1个回答

18

关于SceneKit命中测试

官方文档表示,仅ARKit的hitTest(_:types:)实例方法在iOS 14中已被弃用。然而,在iOS 15中,您仍然可以使用它。ARKit的命中测试方法应该被替换为射线投射方法。

无需寻找SceneKit的hitTest(_:options:)实例方法的替代品,因为它运行良好并返回[SCNHitTestResult]。因此,现在不是将其弃用的时候。

已弃用的SceneKit命中测试方法:

let sceneView = ARSCNView(frame: .zero)

let results: [ARHitTestResult] = sceneView.hitTest(sceneView.center, 
                                            types: .existingPlaneUsingGeometry)


SceneKit射线投射的等效方法

let raycastQuery: ARRaycastQuery? = sceneView.raycastQuery(
                                                      from: sceneView.center, 
                                                  allowing: .estimatedPlane, 
                                                 alignment: .any)

let results: [ARRaycastResult] = sceneView.session.raycast(raycastQuery!)


RealityKit射线投射

如果您需要一种用于命中RealityKit实体的射线投射方法,请使用以下方法:

let arView = ARView(frame: .zero)

let query: CollisionCastQueryType = .nearest
let mask: CollisionGroup = .default
    
let raycasts: [CollisionCastHit] = arView.scene.raycast(from: [0, 0, 0], 
                                                          to: [5, 6, 7],  
                                                       query: query, 
                                                        mask: mask, 
                                                  relativeTo: nil)
    
guard let raycast: CollisionCastHit = raycasts.first else { return }
    
print(raycast.entity.name)

阅读这篇文章,了解如何计算射线的起点方向



1
谢谢您的快速回答!但是,是否有一种方法可以从 let results: [ARRaycastResult] 中获取立方体节点? - aheze
1
明白了。所以基本上,如果我仍在使用ARKit + SceneKit,即使它已被弃用,也应该选择使用命中测试? - aheze
2
ARSCNView对象(ARSCNView类型)有3个hitTest()方法。其中一个已经被弃用,返回[ARHitTestResult] - 用于检测平面的命中测试。第二个hitTest()返回UIView?,第三个返回[SCNHitTestResult],可用于纯SceneKit节点的命中测试。第三种方法没有被弃用 - 您可以将其用于AR应用程序和VR应用程序。因此,在iOS 14的ARSCNView中,您的工具包包括2个hitTest方法和1个raycastQuery()方法。此外,ARSCNView的会话对象允许您对检测到的平面应用射线投射方法。 - Andy Jazz
1
然而,如果你正在使用ARView(RealityKit的视图,ARKit也可以使用),你只能使用射线投射方法 - arView.raycast(...)(返回[ARRaycastResult]),arView.session.raycast(...)(返回[ARRaycastResult]),arView.session.trackedRaycast(...)和2个方法arView.scene.raycast(...) - Andy Jazz
1
hitTestraycast方法不属于协议。您可以在SceneKit节点中使用命中测试,也可以在RealityKit实体中使用射线投射。对于ARKit检测到的平面,您必须使用raycasting - Andy Jazz
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接