前回はUnityからARKitを使う方法と、デモを動かすところまで実行しました。今回はタッチしたところにモデルを配置するプログラムを作ってみましょう。
シーンを作成する
今回も前回ダウンロードしたARKitのUnity用プラグインを使用します。
まだ、入手していない方はこちらからダウンロードしてください。
https://bitbucket.org/Unity-Technologies/unity-arkit-plugin/get/arkit2.0_beta.zip
次に今回作るARKitのアプリ用にシーンを用意します。
/Assets/UnityARKitPlugin/Examples/ARKitSceneを一度開きます。メニューから「File」→「Save Scene as...」を選択して、「Test」という名前で保存しましょう。
これでTestというシーンが新しく作られます。これを使って実験していきましょう。
不要なオブジェクトを削除する
ヒエラルキービューには色々なARKitで使うオブジェクトがすでに配置されています。それぞれに役割がある(各内容は前回の記事参照)のですが、ヤヤコシイので不要なものは削除しましょう。
今回は次のオブジェクトが不要ですので、ヒエラルキービューから削除してください。
- RandomCube
- HitCubeParent
- GeneratePlanes
- ARKitControl
- PointCloudExample
- AR3DOFCameraManager
次のような状態になっていればOKです。PointCloudParticleExampleは検出された特徴点を表示するもので、デバッグ用に便利なので残しています。
タッチを検出するプログラムを作る
続いてタッチを検出するプログラムを作ります。プロジェクトウィンドウで右クリックし、「Create」→「C# Script」を選択してください。ファイル名は「TouchController」にしました。
スクリプトファイルが作成できたら、次のスクリプトを入力してください。
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.XR.iOS; public class TouchController : MonoBehaviour { public GameObject cubePrefab; void HitTest(ARPoint point) { List<ARHitTestResult> hitResults = UnityARSessionNativeInterface .GetARSessionNativeInterface() .HitTest(point, ARHitTestResultType.ARHitTestResultTypeExistingPlaneUsingExtent); // 平面とあたっていた場合 if (hitResults.Count > 0) { GameObject g = Instantiate(cubePrefab); g.transform.position = UnityARMatrixOps.GetPosition(hitResults[0].worldTransform); g.transform.rotation = UnityARMatrixOps.GetRotation(hitResults[0].worldTransform); } } // Update is called once per frame void Update() { if (Input.touchCount > 0 ) { var touch = Input.GetTouch(0); if (touch.phase == TouchPhase.Began) { var screenPosition = Camera.main.ScreenToViewportPoint(touch.position); ARPoint point = new ARPoint { x = screenPosition.x, y = screenPosition.y }; // 平面との当たり判定 HitTest(point); } } } }
Updateメソッドの中でタッチの検出を行っています。タッチされた場合は、ScreenToViewportPointメソッドを使ってタッチ座標をスクリーン座標からビュー座標に変換しています。
平面との当たり判定はHitTestメソッドの中で行っています。当たり判定に関してはUnityの機能ではなくARKitに用意されているHitTestメソッドを使います。
HitTestメソッドの第二引数には当たり判定を行う対象を指定します。指定できるオプションには次のようなものがあります。
オプション名 | 役割 |
---|---|
ARHitTestResultTypeFeaturePoint | ARKittで検出された特徴点 |
ARHitTestResultTypeEstimatedHorizontalPlane | 平面の推定値 |
ARHitTestResultTypeExistingPlane | 検出された平面 |
ARHitTestResultTypeExistingPlaneUsingExtent | 検出された平面の内側領域 |
ここでは、検出された面に対して当たり判定を行いたいので、ARHitTestResultTypeExistingPlaneUsingExtentを指定しています。
タッチした座標が平面とあたっていた場合は、Prefabに登録したモデルのインスタンスを作成しています。SwiftでARKitを使う場合は、SceneKitでNodeを登録・・・ということが必要になりますが、ここらへんが簡単にできるのがUnityの強みですね!
配置する3DモデルのPrefabを作る
配置するモデルは何でもかまわないので、今回はAsset Storeから次のものを利用させていただきました。
Prefabを登録する際は、そのスケールに注意してください。Unityでは標準の立方体(Create→3D Object→Cube)の1辺を1mとして扱うので、その大きさのままARKitで表示してしまうと、大きすぎます。
大きすぎるだけならまだしも、モデルの内側に入っちゃって、あれ表示されてない??なんてこともあるので注意です・・・
最後にスクリプトをアタッチしてPrefabを登録しましょう。ヒエラルキーウインドウのCreate→Create Emptyで空のゲームオブジェクト(Game)を作成し、そこに先程作ったTouchControllerをアタッチしてください。次にインスペクタのPrefab欄に表示したいモデルのPrefabを登録します。
書き出して実行する
これで今回のアプリは完成です。メニューバーから「File」→「BuildSettings」を選択してビルドウインドウを開いてください。Scene In Buildに「Test.scene」をドラッグ&ドロップします。TargetをiOSにしてから、Buildボタンで書き出してください。
実機で実行して画面をタップすると、どんどんリンゴが生成されます🍎🍎🍎
次回は、ARで表示したモデルをより自然に見せるための「光源推定」について紹介します。
参考書
SwiftでARKitの基本的な機能を学べる書籍「SwiftでつくるARKit超入門」を執筆しました!
128ページ、2000円でBOOTHで絶賛発売中です!
booth.pm