В каких случаях ARSCNView.raycastQuery возвращает ноль? - PullRequest
1 голос
/ 05 февраля 2020

В моем делегате рендерера я создаю запрос raycast из центра представления, чтобы отслеживать предполагаемую плоскость, и отображаю 3D-указатель, который следует за результатом raycast.

Это выполняется с помощью view.raycastQuery(from:allowing:alignment:), но возвращает ноль .

Мой вопрос - почему? Нет документации, объясняющей, почему эта функция возвращает значение nil. Я понимаю, что результаты raycast могут быть пустыми, но почему запрос не будет создан?

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
            }
        }
    }
}

1 Ответ

0 голосов
/ 27 марта 2020

Возвращаемое значение ARRaycastQuery? изначально необязательно.

Согласно документации Apple :

raycastQuery(from:allowing:alignment:) метод экземпляра создает луч, который распространяется в положительном направлении. направление z от точки пространства экрана аргумента до определяет, существует ли какая-либо цель аргумента в физической среде где-либо вдоль луча . Если это так, ARKit возвращает трехмерную позицию, где луч пересекает цель.

Если луч не пересекает цель, объекта ARRaycastQuery? нет. Итак, есть nil.

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

Каковы две возможные причины возврата nil?

  • Нет обнаруженной плоскости, куда луч попадает
  • Код логики c неверен

Решение:

Вот как может выглядеть ваш код:

@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!)
}
...