Позиционирующая модель ARKIT - PullRequest
1 голос
/ 19 февраля 2020

У меня проблемы с позиционированием модели на экране. Модель появляется, но появляется над мной, а не передо мной. В идеале я хочу, чтобы модель появлялась там, где ее касали. Пожалуйста, помогите!

Эта функция успешно загружает модель из AWS:

 private func dowloadModel(){
        let url = URL(string: "url_string")!

        URLSession.shared.dataTask(with: url) { data, response, error in

            if let error = error{
                print(error.localizedDescription)
                return
            }

            if let data = data{
                print(data)

                let documentDirectories = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)

                if let documentDirectory = documentDirectories.first{

                    let fileURL = documentDirectory.appendingPathComponent("Food.scn")
                    let dataNS : NSData? = data as NSData

                    try! dataNS?.write(to: fileURL, options: .atomic)

                    print("Saved!")
                }
            }

        }.resume()
    }

Здесь я отображаю модель на экране:

private func registerGestureRecogniser(){
        print("Tapped")
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
        self.sceneView.addGestureRecognizer(tapGestureRecognizer)
    }

Вот нажатая функция:

 @objc func handleTap(gesture: UITapGestureRecognizer) {

        let documentDirectories = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)

        if let documentDirectory = documentDirectories.first{
            let fileURL = documentDirectory.appendingPathComponent("Food.scn")

            do{
                let scene = try SCNScene(url: fileURL, options: nil)
                let node = scene.rootNode.childNode(withName: "Burger", recursively: true)!

                node.position = SCNVector3Make(0, 0, 0);

                self.sceneView.scene.rootNode.addChildNode(node)
            }
            catch{
                print(error)
            }

        }
    }

Я также получаю сообщение об ошибке:

Error: Failed to load <C3DImage

1 Ответ

1 голос
/ 19 февраля 2020

Когда вы делаете

node.position = SCNVector3Make(0, 0, 0);
self.sceneView.scene.rootNode.addChildNode(node)

, вы позиционируете узел модели в корневом узле сцены, положение которой определяется ARKit при запуске сцены.

Если вы хотите, чтобы модель отображалась перед камерой, вам нужно взять преобразование камеры (session.currentFrame?.camera.transform), изменить компонент -z и установить его в качестве позиции узла. Или, если вы хотите разместить вашу модель на поверхности, выполните raycast и используйте raycastResult simdWorldPosition в качестве simdWorldPosition вашего * узла.

Определенно есть примеры raycast вокруг, но в Короче говоря, сначала нужно определить запрос:

let bounds = sceneView.bounds
let screenCenter = CGPoint(x: bounds.midX, y: bounds.midY)
let query = sceneView.raycastQuery(from: screenCenter, allowing: .estimatedPlane, alignment: .horizontal)

Вышеприведенное описание определяет лучевую трансляцию, простирающуюся от центра экрана и находящую только горизонтальные поверхности. Пожалуйста, изучите документы для получения дополнительной информации о allowing и alignment вариантах.

Затем вы можете использовать session, чтобы разыграть свой луч:

session.raycast(query)

Это вернет массив ARRaycastResult. Вы можете просмотреть их и выбрать, если вы sh, но я обычно просто беру .first один (примечание: он может быть пустым).

Затем вы захотите взять компонент перевода вашего raycastResult преобразовать и назначить его как simdWorldPosition вашего узла. Обратите внимание, что вы можете назначить все преобразование узлам simdWorldTransform, но это также изменит ориентацию вашего узла, что вы можете или не хотите делать.

if let raycastResult = session.raycast(query).first {
    node.simdWorldPosition = raycastResult.worldTransform.translation
}

О, я также нахожу это маленьким расширение для удобства:

extension float4x4 {
    /**
     Treats matrix as a (right-hand column-major convention) transform matrix
     and factors out the translation component of the transform.
    */
    var translation: SIMD3<Float> {
        let translation = columns.3
        return SIMD3<Float>(translation.x, translation.y, translation.z)
    }
}

Это то, что позволяет вам сделать worldTransform.translation в моем коде выше.

...