第2章 ARKit 堤 修一/@shu223
見てのとおり、タップイベントの取得処理はUIKitを用いているだけです。平面ジオメトリを持つ子ノードの探索部分は従来からあるSceneKitの実装ですし、ARKitとして新たに出てきたのは、上で解説したARSCNViewのhitTest(_:types:)メソッドとARHitTestResultのanchorプロパティ以外では、コード内コメント(1)の、アンカーに対応するノードをARSCNViewのnode(for:)メソッドを利用して取得している部分ぐらいです。
サンプルを実行して、画面内に水平面が検出されている状態で水平面をタップすると、水平面の色が一時的に変わります。
図2.10 ARKitで検出された水平面のインタラクション
■SCNSceneRendererのhitTest(_:options:)メソッドによるヒットテスト
前項で解説したARSCNViewが備えているヒットテストの機能は、ARKitによって検出できる特徴点や平面が判定の対象となりますが、実はSceneKitのSCNSceneRendererプロトコルにもヒットテストのメソッドが定義されています。ARSCNViewはSCNSceneRendererプロトコルに準拠しているSCNViewを継承しているので、こちらのメソッドも利用できます。
func hitTest(_ point: CGPoint, options: [SCNHitTestOption : Any]? = nil) -> [SCNHitTestResult]
前項で解説したヒットテストとの大きな違いは、SceneKitのシーングラフ内にあるノードがヒットテスト対象になる、という点です。検出した水平面ではなく、その水平面上に設置した仮想オブジェクトのノードに対してインタラクションを可能にしたい場合には、こちらのSceneKitのヒットテストの方が向いているといえます。
実装は次のようになります。
// ヒットテストのオプション設定 let hitTestOptions = [SCNHitTestOption: Any]() // ヒットテスト実行 let results: [SCNHitTestResult] = sceneView.hitTest(pos, options: hitTestOptions) // ヒットしたノードに合致する仮想オブジェクトはあるか、再帰的に探す guard let virtualNode = virtualObjectNode else {return} for result in results { for child in virtualNode.childNodes { guard child == result.node else {continue} virtualNode.react() // 該当するノードに反応させる return } }