定位ARKIT模型

Positioning ARKIT model

我在屏幕上定位模型时遇到一些问题。模型出现了,但它出现在我上方而不是在我面前。理想情况下,我希望模型出现在它被点击的地方。请帮忙!

此函数成功从 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

当你

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

您正在将模型节点定位在场景的根节点上,其位置在场景启动时由 ARKit 确定。

如果你想让模型出现在摄像头前面,那么你需要抓取摄像头变换(session.currentFrame?.camera.transform),修改-z组件,并将其设置为节点的位置.或者,如果您想将模型放置在表面上,请进行光线投射并使用 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)

以上定义了从屏幕中心延伸并仅找到水平表面的光线投射。请浏览 docs 以获取有关 allowingalignment 选项的更多信息。

然后您可以使用 session 投射光线:

session.raycast(query)

这将 return 一个 ARRaycastResult 的数组。您可以检查它们并根据需要进行选择,但我通常只选择 .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