おもちゃラボ

Unityで遊びを作ってます

Unityで始めるARKit入門 モデル配置編

前回はUnityからARKitを使う方法と、デモを動かすところまで実行しました。今回はタッチしたところにモデルを配置するプログラムを作ってみましょう。

f:id:nn_hokuson:20180920201828j:plain

シーンを作成する

今回も前回ダウンロードした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」という名前で保存しましょう。

f:id:nn_hokuson:20180920195520p:plain:w350

これでTestというシーンが新しく作られます。これを使って実験していきましょう。

不要なオブジェクトを削除する

ヒエラルキービューには色々なARKitで使うオブジェクトがすでに配置されています。それぞれに役割がある(各内容は前回の記事参照)のですが、ヤヤコシイので不要なものは削除しましょう。

nn-hokuson.hatenablog.com

今回は次のオブジェクトが不要ですので、ヒエラルキービューから削除してください。

  • RandomCube
  • HitCubeParent
  • GeneratePlanes
  • ARKitControl
  • PointCloudExample
  • AR3DOFCameraManager

次のような状態になっていればOKです。PointCloudParticleExampleは検出された特徴点を表示するもので、デバッグ用に便利なので残しています。

f:id:nn_hokuson:20180920195539p:plain:w270

タッチを検出するプログラムを作る

続いてタッチを検出するプログラムを作ります。プロジェクトウィンドウで右クリックし、「Create」→「C# Script」を選択してください。ファイル名は「TouchController」にしました。

f:id:nn_hokuson:20180920195549p:plain:w270

スクリプトファイルが作成できたら、次のスクリプトを入力してください。

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を登録します。

f:id:nn_hokuson:20180920200407j:plain

書き出して実行する

これで今回のアプリは完成です。メニューバーから「File」→「BuildSettings」を選択してビルドウインドウを開いてください。Scene In Buildに「Test.scene」をドラッグ&ドロップします。TargetをiOSにしてから、Buildボタンで書き出してください。

f:id:nn_hokuson:20180920200538j:plain:w400

実機で実行して画面をタップすると、どんどんリンゴが生成されます🍎🍎🍎

f:id:nn_hokuson:20180920202146g:plain:w500

次回は、ARで表示したモデルをより自然に見せるための「光源推定」について紹介します。

nn-hokuson.hatenablog.com

参考書

SwiftでARKitの基本的な機能を学べる書籍「SwiftでつくるARKit超入門」を執筆しました!
128ページ、2000円でBOOTHで絶賛発売中です!
booth.pm