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

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

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

2018年07月23日 19時00分

仮の光源を設定して、3Dオブジェクトがそれらしく見えるようにする

 この赤いボールの表示を見て、何かしらの不自然さを感じる人は多いでしょう。というよりも、ほとんどの人はそう感じるはずです。赤い球だと言われれば、位置関係からそう思えなくもないだけで、冷静に見てみれば、単に赤くベタ塗りされた円が現実世界の映像の上に重なっているようにしか思えないからです。

 球体のはずの物体の表面の色がまったく一様では、違和感を与えるのは当然です。立体物であれば、光を反射して明るく見える部分や、逆に影になって暗く見える部分があるはずです。球体のノードを置いただけでは、球の周囲の全方向から一様の光が当たっているという、実際にはあり得ない状態になっているのです。

 このあたりはARというよりも、純粋な3Dグラフィックの問題ですが、こうした不自然さを解消するには、照明という概念を導入する必要があります。物体と同じ空間内のどこかに照明を配置して、その光の反射や影の効果を描くのです。

 とはいえ、今回の主役はあくまでARであって、それによって認識した現実世界の形状に合わせて3Dオブジェクトを配置してみることが目的です。実はシーンビュー(ARSCNView)には、細かな設定なしに適当な照明を配置して、3Dオブジェクトをそれらしく見せるための便利な自動照明機能が備わっています。

 それはシーンビューのautoenablesDefaultLightingというプロパティをtrueに設定するだけで実現できます。念のためにもう1つ、automaticallyUpdateLighingのプロパティもtrueに設定して、より自然な照明に見えるようにします。

シーンビューが検出した面の情報を得るために、まずビューコントローラーをシーンビューのデリゲートに設定します。そのためには、まずARSCNViewDelegateのプロトコルに準拠させる必要があります

 この結果、球体の表面には、明るい部分と暗い部分ができて、立体的に見えるようになりました。

自動照明機能をオンにすると、球には光と影の表現が加わって、床に置かれたボールに見えるようになりました。ただし、現実世界の光を検出して合わせているわけではないので、まったく自然に見えるところまではいきません

モデリングした3Dオブジェクトを配置する

 平面や球ならば、その場でプログラムによって簡単に生成できます。しかし、もっと複雑な形状の3Dオブジェクトは、3Dモデリングのアプリケーションを使って作成したモデルファイルを読み込んでノードに変換するのが普通です。とはいえ、ここで1から3Dモデリングの方法を解説するわけにもいきません。そこで、ダウンロード可能なフリーの3Dモデルを利用して、シーンビューの中に表示してみることにしましょう。

 無料の3Dモデルを入手可能なサイトは、いくつかありますが、ここではfree3d.comを利用してみました。

少し複雑な形状の3Dオブジェクトを配置するために、フリーの3Dモデルを提供しているFree3D(https://free3d.com/)のサイトにアクセスして、少なめのポリゴンで描かれた自動車のモデルをダウンロードしました

 このサイトでは、まずモデルの種類を選び、そのフォーマットや特徴などによって絞り込むことができます。ここでは、「Vehicles(乗り物)」のカテゴリーを選んだあと、「Lowpoly(ポリゴン数が少ないもの)」を選択して、比較的単純な「Low-Poly Car」という自動車のモデルを見つけました。ARKitで扱うモデルファイルとして適しているのは、拡張子が「.dae」のCOLLADAフォーマットと呼ばれるものです。このフォーマットを含むモデルを選びましょう。

 ARKitは、非現実の3Dグラフィック部分はSCNKitに依存しています。そのSCNKitで扱える標準的なモデルファイルのフォーマットはApple独自の「.scn」です。しかし、世の中に出回っているサンプルプログラムを見ると、.daeのファイルもSCNSceneクラスのオブジェクトを生成する際に、名前を指定するだけで簡単に読み込めるようになっています。ただし、それはXcodeを使ってビルドするアプリの場合の話です。Xcodeはプロジェクトに追加された.daeファイルを、自動的に(見えないところで).scnに変換しているのです。

 Swift Playgroundsでは、それができないので、直接.daeを読み込むのは困難です。SCNSceneSourceというクラスを利用すれば、.daeを読み込んでシーンを作成することも可能なはずなのですが、今のところうまくいっていません。そこで、とりあえずXcodeの力を借りて.daeを.scnに変換してからプレイグラウンドに取り込んで利用することにしました。.daeをXcodeで開くと、専用のウィンドウが表示されます。そこで「File」メニューから「Export...」を選んでフォーマットを.scnに指定して保存します。

ダウンロードした圧縮ファイルの中から、.daeという拡張子のファイルを取り出して、Xcodeで開いてみます。Swift Playgrounds環境では直接読み込むのが難しいので、Xcodeの書き出し機能を使って.scnファイルに変換します

 今回は、こうして得られた「Car.scn」ファイルを、いつものようにiCloudドライブ経由でプレイグラウンドに読み込んでいます。なお、.daeファイルはmacOSの「プレビュー」で開いて内容を確認することもできます。ただしプレビューでは、画像ファイルにしか変換できないのが残念なところです。

 用意した「Car.scn」ファイルは、viewDidLoadメソッドの中で、SCNSceneのオブジェクトとして作成し、プロパティのcarSceneに代入しておきます。

プレイグラウンドに取り込んだ.scnファイルは、viewDidLoadの中でシーンオブジェクトに変換し、追加したプロパティcarSceneに代入しておきます

 その後、rendererメソッドの中では、平面と球体の描画はやめて、carSceneから作ったノードだけを配置することにしました。その際には、ちょうどプラモデルの車のようにスケールを1/20にして、水平面と角度が合うように、x軸を中心に-90度ほど回転させています。

rendererメソッドの中では、carSceneからノードを取り出し、それを検出した平面の中央に配置します。このノードも、見た目の座標系に対して90度回転しているので、配置する前にx軸を中心に-90度回転させ、スケールも1/20にしてセットします

 このプログラムを動かして平面を検出させると、その中央にプラモデルサイズの赤い車が表示されるはずです。

これで、検出した水平面の上に、ちょうど乗った自動車のモデルが表示されるようになりました。自動照明効果による明暗も付けられています。これくらいの表示クオリティなら、ゲームとしての使用にも耐えられそうです

 この例でも自動照明はオンにしてあるので、それらしいシェーディングの付いた3Dオブジェクトとなっています。

次回の予定

 今回は、前回に実現した水平面の検出機能を利用して、その上にボールや自動車のモデルを配置してみました。また簡単に使える照明機能を設定して、3Dオブジェクトを立体的に見せる方法も試しました。ここまでARKitを使ってみると、それを使いこなすには、非現実部分の3Dオブジェクトを扱うSCNKitを理解することが不可欠であることに気付くでしょう。

この連載では、これまでSCNKitを扱っていませんでした。そこで次回は、いったんSCNKitに話題を転換して、iOSにおける3Dオブジェクトの扱いを見直してみることにします。SCNKitは、ARKitが使えない古めのiPadでも動くので、ARKitは傍観していた読者の方々も再び参加していただければと思います。

mobileASCII.jp TOPページへ