このページの本文へ

Swift Playgroundsで学ぶiOSプログラミング第95回

ARKitで3Dオブジェクトを配置する

現実世界の床にボールや自動車のモデルを配置する

2018年07月23日 19時00分更新

文● 柴田文彦 編集●吉田ヒロ

  • この記事をはてなブックマークに追加
  • 本文印刷

 このところARKitを利用するプログラムに取り組んでいます。最初はほとんどARKitが動作するかどうかだけを確かめるようなプログラムから始めました。

 というのも、すでに述べたように、ARKitは、Swift Playgroundsが利用可能なすべてのiPadで動作するとは限らないからです。そして前回は、カメラで撮影中の現実世界の中の水平面を検出する機能をプログラムしてみました。現実世界の(映像の)中に、非現実世界の3Dオブジェクトなどを自然な感じで配置するには、現実世界の地面、あるいは床やテーブルの位置や形状に基づいて、非現実世界の座標系を設定する必要があるからです。

 前回は、検出した水平面の位置と大きさに合わせて、ちょうどシートを敷くように、半透明の緑色の平面を配置していました。それによって、水平面がうまく検出できたことは確認できたものの、それだけではAR(拡張現実)の効果として寂しい絵であったことは否めません。そこで、今回は単なる水平面の検出と確認から脱却して、形のある立体的な3Dオブジェクトを配置してみることにします。

 ARKitの初回には、文字列から生成した3Dオブジェクトをやみくもに空中に配置していましたが、2回目で水平面が検出できるようになりました。そこで3回目の今回は、それらを組み合わせて地面や床、あるいはテーブル上に置いたように見える3Dオブジェクトを配置してみようというわけです。

 まずは、3Dオブジェクトとしては最もシンプルな球体を置いてみます。その後、3Dのモデリングアプリで作成した比較的複雑な形状のオブジェクトを配置してみましょう。これらは、オブジェクトの複雑さ(データ量)としてはかなり異なりますが、ARKitを利用したプログラム上の処理の手順としては、それほど大きく変わることはありません。

検出した水平面に沿った平面の代わりに球体を配置する

 今回の最初のプログラムは、前回の最終的なものより、むしろシンプルな状態からスタートします。前回の平面検出では、いったん検出できた平面に対しても、その後のカメラの動きによってさらに広い領域が検出できた場合にアップデートを実行していました。具体的には、rendererのdidAddメソッドで最初に検出した平面を画面に表示し、さらにdidUpdateメソッドによって追加された情報を使って大きさを修正していました。今回は、didAddメソッドだけを実装して、最初に検出した平面の中央にオブジェクトを配置することにします。

 プログラムの最初の部分は、前回のものと何も変わりません。

今回は、前回の最終的なプログラムとほぼ同じところから始めます。ただし、いったん検出した水平面をアップデートする機能は省くので、rendererのdidUpdateメソッドは実装しません

 ざっと復習すると、ビューコントローラーのプロパティとして、ARKitが提供するシーンビューを用意し、viewDidLoadメソッドの中で、そのシーンビューをビューコントローラーのビューに置き換えます。つまり、プレイグラウンド画面にはシーンビューだけを表示するようにします。

 viewWillAppearメソッドの中では、現実世界の水平面の検出機能をオンにして、シーンビューのセッションを起動します。また、水平面が検出された際には、このビューコントローラー内のデリゲートメソッド、rendererが呼び出されるように設定しています。

 そのrendererのdidAddメソッドの中で、検出した水平面上にオブジェクトを配置していきます。とりあえず、前回に描いた半透明の緑の平面はそのまま残し、その上に赤いボールを配置してみることにしましょう。

rendererのdidAddメソッドでは、前回と同じように検出した水平面に合わせて半透明の緑の平面を配置します。その中央に、赤いボールに見えることを狙って、球体のノードとして追加しています

 ボールは、まず球体(Sphere)として、半径だけを指定してSCNSphereクラスのオブジェクトを作ります。そして、そこに赤い色を設定し、それからノード(SCNNode)を作成します。さらにそのノードの位置を設定してから、メソッドに渡されてきた全体のノードに、子ノードとしてセットします。

 プログラムの他の部分は、前回のものと同じです。これで、平面を検出すると、緑のシートの上に赤いボールが表示されるはずです。しかし、実際に表示されたボールは、ちょうど南半球(下半分)が、緑のシートの下に潜り込んだようになってしまいました。

確かに緑の半透明のシートの中央に赤い球が配置されました。しかし、球の下半分が平面の下にもぐってしまっています。これは球の中心が平面の中央に一致するように配置したからです

 球体の位置は、検出した平面の中央に設定したのですが、それは球の中心の点となるので、当然と言えば当然の結果です。球が平面の上に乗っている、つまり球の表面が平面に接しているように配置するには、球の位置を、その半径分だけ上に持ち上げる必要があります。そのためには、球の位置の高さ方向を表すy軸の座標に、球の半径と同じ0.05を加えれば良いのです。

球の位置を設定するベクトルのy座標の値に、球の半径である0.05を加えることで、球が平面の上に乗っているように見えるようになりました。z軸ではなくy軸なのは、球の座標系も見た目の座標系に対して90度回転しているからです

 これで、赤いボールが緑のシートの上に、言い換えれば床の上に、ちょうど乗っているように見えるはずです。

この連載の記事

週間ランキングTOP5

ASCII倶楽部会員によく見られてる記事はコレだ!

ASCII倶楽部の新着記事

会員専用動画の紹介も!