第2章 ARKit 堤 修一/@shu223
表2.6 ARHitTestResult.ResultTypeのタイプと概要説明
タイプ名 |
結果のタイプ |
featurePoint |
ARKitによって抽出される特徴点 |
existingPlane |
検出済みの平面アンカー(平面のサイズはヒットテストに考慮されない) |
existingPlaneUsingExtent |
検出済みの平面アンカー(平面のサイズがヒットテストに考慮される) |
estimatedHorizontalPlane |
推定の水平面 |
本節では「検出済みの平面」をヒットテスト対象にするため、existingPlaneUsingExtentを指定します。
let results = sceneView.hitTest(pos, types: .existingPlaneUsingExtent)
ここでexistingPlaneを指定しても、検出済みの平面をヒット対象にしたヒットテストを実施できます。ただしこのexistingPlaneは、平面アンカーのextent(大きさの情報が入っている)を使用しない、つまり無限にその平面が広がっているものとしてヒットテストが行われます。
なお、ARHitTestResult.ResultTypeはOptionSetに準拠しているので、複数タイプの指定も可能です。
let results = sceneView.hitTest(pos, types: [.existingPlane, .estimatedHorizontalPlane])
ヒットテストの結果はARHitTestResult型の配列となっています。配列になっている理由は、タッチした先には奥行きがあるため、奥行きの異なる複数のオブジェクトが同時にヒットする可能性があるためです。配列に格納されたARHitTestResultオブジェクトは、カメラに近い順でソートされています。
ヒットテストのタイプとしてexistingPlaneUsingExtentまたはexistingPlaneを指定した場合、ARHitTestResultのanchorプロパティに、ヒットした面のアンカーが入ってきます。
var anchor: ARAnchor? { get }
具体的な実装を見てみましょう。画面のタップ位置からヒットテストを行い、ヒットした平面のうちもっともカメラに近い平面に反応させるコードは次のようになります。
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { // タップ位置のスクリーン座標を取得 guard let touch = touches.first else {return} let pos = touch.location(in: sceneView) // 平面を対象にヒットテストを実行 let results = sceneView.hitTest(pos, types: .existingPlaneUsingExtent) // ヒット結果のうち、もっともカメラに近いものを取り出す if let result = results.first { // ヒットした平面のアンカーを取り出す……(1) guard let anchor = result.anchor else {return} // アンカーに対応するノードを取得 guard let node = sceneView.node(for: anchor) else {return} // 平面ジオメトリを持つ子ノードを探して反応させる(略) } }