【问题标题】:Project Point method: converting rawFeaturePoint to Screen SpaceProject Point 方法:将 rawFeaturePoint 转换为 Screen Space
【发布时间】:2022-01-15 10:02:00
【问题描述】:

大家好,我想了解使用 ARKit 的 projectPoint 函数时返回给我的值。

我的目标是采取一个点p = (x,y,z),其中元组中的所有值都在[-1, 1] 范围内,并将其转换为p' = (x',y'),其中该对中的所有值都在[0,1] 范围内,即项目来自世界空间到屏幕/图像空间。

我知道arframe.camera.imageResolution = (1920.0, 1440.0),并且 我知道我的屏幕尺寸是(390.0 ,844.0)

所以,当我使用我写的函数时:arframe.camera.projectPoint(point: p, orientation: .portrait, viewportSize: arframe.camera.imageResolution

这会返回(x, y),但有时会出现x > 1440.0y > 1920.0。 此外,有时xy 是负值。

我对函数如何返回大于我们给出的视口大小的值感到困惑。我也对为什么这些值本身是负数感到困惑。

Apple 提供的文档说明该函数“将点从 ARKit 检测到的 3D 世界空间的投影返回到渲染场景的视图的 2D 空间。”

“渲染场景的二维空间”是什么意思?

【问题讨论】:

    标签: swift arkit


    【解决方案1】:

    理论

    func projectPoint(_ point: simd_float3, 
                  orientation: UIInterfaceOrientation, 
                 viewportSize: CGSize) -> CGPoint
    

    Xcode小技巧说——实例方法projectPoint(...)返回指定点投影到原点在左上角且大小与viewportSize参数一致的2D像素坐标空间。

    Screen SizeViewport size 之间的区别描述为 HereHere(我看到你说你知道这一点)。

    解决方案

    诀窍在于,只有当 3D 点在相机的frustum 的覆盖范围内时,才能正确投影 2D 点——根据勾股定理计算距离并不是什么秘密。 .

    import ARKit
     
    extension ViewController: ARSessionDelegate {
        
        func session(_ session: ARSession, didUpdate frame: ARFrame) {
            
            let point = simd_float3(0.3, 0.5,-2.0)
            
            if self.sceneView.isNode(self.sphere,
                                 insideFrustumOf: self.sceneView.pointOfView!) {
                
                let pp = frame.camera.projectPoint(point,
                                      orientation: .portrait,
                                     viewportSize: CGSize(width: 375, height: 812))
    
                self.label_A.text = String(format: "%.2f", pp.x / 375)
                self.label_B.text = String(format: "%.2f", pp.y / 812)
            }
        }
    }
    

    如您所见,输出归一化坐标(0.00 ... 1.00)的值非常简单:

    class ViewController: UIViewController {
    
        @IBOutlet var sceneView: ARSCNView!
        @IBOutlet var label_A: UILabel!
        @IBOutlet var label_B: UILabel!
        let sphere = SCNNode(geometry: SCNSphere(radius: 0.1))
        
        override func viewDidLoad() {
            super.viewDidLoad()
    
            sceneView.session.delegate = self
            sceneView.scene = SCNScene()
            
            sphere.geometry?.firstMaterial?.diffuse.contents = UIColor.green
            sphere.position = SCNVector3(0.3, 0.5,-2.0)
            sceneView.scene.rootNode.addChildNode(sphere)
            
            let config = ARWorldTrackingConfiguration()
            sceneView.session.run(config)
        }
    }
    

    我使用了 iPhone X 参数——垂直 viewportSize 为 375 x 812。

    【讨论】:

    • 嗨,安迪,感谢您的回复。但是,我没有使用SCNScene,因此我无法轻松检查p 是否在相机的未来主义范围内。相反,您认为我可以根据值过滤点吗,v,返回的projectPoint() 函数,即如果0 < v.x < screenWidth0 < v.y < screenHeight,那么我知道p 在相机的未来主义中。跨度>
    • 嗨,尼古拉斯。您没有明确指出您使用的是哪个渲染框架,所以我得出结论是 ARKIt + SceneKit。
    • 这是一个很棒的资源,包含平面提取的数学 - web.archive.org/web/20120531231005/http://crazyjoke.free.fr/doc/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-18
    • 2020-07-30
    • 1970-01-01
    • 2021-03-26
    相关资源
    最近更新 更多