06ee5aad8e355870632746d7d93a54b1
ARKit 中用好 unprojectPoint: 效率又提升一倍

unprojectPoint 作用

unprojectPoint 的作用其实很类似hitTest方法,都是从屏幕指定位置发射射线,与 3D 空间某处相交,得到交点。

不同的是:

  • hitTest方法是射线与某个SCNGeometry相交,返回所在的 SCNNode 和交点信息;
  • unprojectPoint 是将屏幕上的点投影到一个3D 空间内的平面上,可脱离 SCNNode 类和 SCNGeometry 类来使用。

注意:SceneKit 中SCNSceneRenderer协议(SCNView实现了这个协议)也提供了一个unprojectPoint方法,但是这个方法只能将屏幕上的点,投影到视锥体的平面上,z 是 0 则投影到 zNear 平面上,z 是 1 则投影到 zFar 平面上。

ARKit 中提供了两个unprojectPoint 方法:一个在ARSCNView类下,一个在ARCamera类下。并且官方文档中说明了,ARSCNView类下的方法,其实就是调用了ARCamera类的方法,只是ARSCNView类自己知道自己的 size 和 orientation,所以少了两个参数。

// 官方文档说明了ontoPlane是指:投影到 4x4 矩阵的 xz 平面上
extension ARCamera {
    @available(iOS 12.0, *)
    @nonobjc public func unprojectPoint(_ point: CGPoint, ontoPlane planeTransform: simd_float4x4, orientation: UIInterfaceOrientation, viewportSize: CGSize) -> simd_float3?
}

@available(iOS 12.0, *)
extension ARSCNView {
    @nonobjc public func unprojectPoint(_ point: CGPoint, ontoPlane planeTransform: simd_float4x4) -> simd_float3?
}

示例用法

当我们想要在 AR 空间确定一个位置时,就可以用unprojectPoint来处理:
比如,在 3D 空间放置一个小球。我们先创建一个平面,然后从屏幕中点投影到平面上,在交点处放置一个小球:
```swift
// plane 在 xy 平面,是竖直的
let planeNode = SCNNode(geometry: SCNPlane(width: 1, height: 1))
planeNode.geometry?.firstMaterial?.diffuse.contents = UIColor(white: 1, alpha: 0.8)

top Created with Sketch.