理论
func projectPoint(_ point: simd_float3,
orientation: UIInterfaceOrientation,
viewportSize: CGSize) -> CGPoint
Xcode小技巧说——实例方法projectPoint(...)返回指定点投影到原点在左上角且大小与viewportSize参数一致的2D像素坐标空间。
Screen Size 和 Viewport size 之间的区别描述为 Here 和 Here(我看到你说你知道这一点)。
解决方案
诀窍在于,只有当 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。