第2章 ARKit 堤 修一/@shu223


 コード内コメント(1)で示した行で、平面ジオメトリを作成する際に、そのサイズをARPlaneAnchorextentプロパティのxzだけから決定しています。この理由については 「2.3.2 平面検出に関するイベントをフックする - ARSessionDelegate」で解説しました。

 (2)で示した行では、「平面ジオメトリを持つノード」を、x軸まわりに90度回転させています。これはSCNPlaneジオメトリはデフォルトではx-y平面に対して作成されるので、それをx-z平面(=ARKit/SceneKitの座標系における水平面)に重なるようにするためです。

 前節で現実世界の水平面を検出できるようになりました。次は、その検出した水平面に3Dモデルを仮想オブジェクトとして設置してみましょう。

 ここまでの節で、ARSCNViewSCNSceneオブジェクトを持っており、ARSCNViewDelegateのデリゲートメソッドから、検出した平面アンカーに対応するSCNNodeオブジェクトが取得できることは解説しました。あとは仮想オブジェクトとしてのSCNNodeを子ノードとして載せるだけです。

 仮想オブジェクトとしてどのような3Dモデルを利用するか、そのノードをどのように扱うかはすべてSceneKitの役割であり、ARKitには依存しません。言い換えると、従来からある実装方法やアセットを利用できる、ということになります。

 では、具体的な実装を見ていきましょう。

サンプルコード:03_VirtualObject

2.4.1 3Dモデルを読み込む

 まず、仮想オブジェクトとして設置する3Dモデルを読み込みます。.scnファイルから読み込む場合は、SCNSceneのイニシャライザを利用できます。

// シーンファイルからシーンを生成
let scene = SCNScene(named: "filename.scn", inDirectory: "directoryname")!
// 生成したシーンのrootNode配下の子ノードを別のノードに載せ替える
let virtualObjectNode = SCNNode()
for child in scene.rootNode.childNodes {
    virtualObjectNode.addChildNode(child)
}

 シーンファイルから生成したSCNSceneオブジェクトのrootNode配下の子ノードを別のノードに載せ替えています。これは、ARSCNViewが保持しているシーンのノード階層下に置けるようにするための、従来どおりの(ARKit登場以前からある)手法です。

 SCNSceneSourceクラスを利用すれば、.daeなど他のファイルフォーマットから読み込むこともできます。

let url = Bundle.main.url(forResource: "filename", withExtension: "dae")!
let sceneSource = SCNSceneSource(url: url, options: nil)!
let virtualObjectNode = sceneSource.entryWithIdentifier("modelId", withClass: SCNNode.self)!

iOS 11 Programming

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