【问题标题】:In which cases ARSCNView.raycastQuery returns nil?在哪些情况下 ARSCNView.raycastQuery 返回 nil?
【发布时间】:2020-02-05 10:08:12
【问题描述】:

在我的渲染器委托中,我从视图中心创建了一个光线投射查询,以跟踪估计的平面并显示一个跟随光线投射结果的 3D 指针。

它是通过view.raycastQuery(from:allowing:alignment:) 完成的,但返回 nil。

我的问题是为什么?没有文档说明为什么这个函数会返回一个 nil 值。我知道光线投射结果可能为空,但为什么不会创建查询?

func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
    guard view.session.currentFrame?.camera.trackingState == .normal else {
        return
    }
    DispatchQueue.main.async {
        let center = view.center
        DispatchQueue.global(qos: .userInitiated).async {
            if let query = view.raycastQuery(from: center, allowing: .estimatedPlane, alignment: .any) {
                let results = view.session.raycast(query)
                ...
            }
            else {
                // sometimes it gets here
            }
        }
    }
}

【问题讨论】:

    标签: swift augmented-reality scenekit arkit hittest


    【解决方案1】:

    可返回的ARRaycastQuery? 最初是可选的。

    据苹果documentation

    raycastQuery(from:allowing:alignment:) 实例方法创建一条从参数屏幕空间点沿正 z 方向延伸的射线,以确定任何参数目标是否存在于沿射线的物理环境中的任何位置 .如果是这样,ARKit 会返回射线与目标相交的 3D 位置。

    如果射线不与目标相交,则没有ARRaycastQuery? 对象。所以有nil

    func raycastQuery(from point: CGPoint, 
                 allowing target: ARRaycastQuery.Target, 
                       alignment: ARRaycastQuery.TargetAlignment) -> ARRaycastQuery?
    

    返回nil的两个可能原因是什么?

    • 没有检测到射线击中的平面
    • 代码逻辑错误

    解决方案:

    您的代码可能如下所示:

    @IBOutlet var sceneView: ARSCNView!
    
    @IBAction func onTap(_ sender: UIGestureRecognizer) {
    
        let tapLocation: CGPoint = sender.location(in: sceneView)
        let estimatedPlane: ARRaycastQuery.Target = .estimatedPlane      
        let alignment: ARRaycastQuery.TargetAlignment = .any
    
        let query: ARRaycastQuery? = sceneView.raycastQuery(from: tapLocation,
                                                        allowing: estimatedPlane,
                                                       alignment: alignment)
    
        if let nonOptQuery: ARRaycastQuery = query {
    
            let result: [ARRaycastResult] = sceneView.session.raycast(nonOptQuery)
    
            guard let rayCast: ARRaycastResult = result.first
            else { return }
    
            self.loadGeometry(rayCast)
        }
    }
    

    还有一个获取模型的方法:

    func loadGeometry(_ result: ARRaycastResult) {
    
        let scene = SCNScene(named: "art.scnassets/myScene.scn")!
    
        let node: SCNNode? = scene.rootNode.childNode(withName: "model", 
                                                   recursively: true)
    
        node?.position = SCNVector3(result.worldTransform.columns.3.x,
                                    result.worldTransform.columns.3.y,
                                    result.worldTransform.columns.3.z)
    
        self.sceneView.scene.rootNode.addChildNode(node!)
    }
    

    【讨论】:

    • 如你所说,There's no detected plane where ray hits。但是在知道没有检测到命中(又名 raycast 结果)之前,raycast 查询应该是raycast-ed。你谈结果,我谈查询。另外,sceneView.session.raycast(query!) 可能由于强制解包而崩溃,因为查询可以为零,这是我想知道的:为什么 查询 可能为零?
    • 我已经更正了我的答案。它是raycastQuery() 确定物理环境中是否存在任何目标,而不是raycast() 方法。这就是为什么它可能是ARRaycastQuerynil
    猜你喜欢
    • 2015-08-03
    • 1970-01-01
    • 1970-01-01
    • 2020-10-10
    • 2023-03-12
    • 1970-01-01
    • 2022-01-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多