第2章 ARKit 堤 修一/@shu223


 見てのとおり、タップイベントの取得処理はUIKitを用いているだけです。平面ジオメトリを持つ子ノードの探索部分は従来からあるSceneKitの実装ですし、ARKitとして新たに出てきたのは、上で解説したARSCNViewhitTest(_:types:)メソッドとARHitTestResultanchorプロパティ以外では、コード内コメント(1)の、アンカーに対応するノードをARSCNViewnode(for:)メソッドを利用して取得している部分ぐらいです。

 サンプルを実行して、画面内に水平面が検出されている状態で水平面をタップすると、水平面の色が一時的に変わります。

図2.10 ARKitで検出された水平面のインタラクション

SCNSceneRendererのhitTest(_:options:)メソッドによるヒットテスト

 前項で解説したARSCNViewが備えているヒットテストの機能は、ARKitによって検出できる特徴点や平面が判定の対象となりますが、実はSceneKitのSCNSceneRendererプロトコルにもヒットテストのメソッドが定義されています。ARSCNViewSCNSceneRendererプロトコルに準拠している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
    }
}

iOS 11 Programming

  • 著者:堤 修一,吉田 悠一,池田 翔,坂田 晃一,加藤 尋樹,川邉 雄介,岸川 克己,所 友太,永野 哲久,
  • 製本版,電子版
  • 続きを読む