おもちゃラボ

Unityで遊びを作ってます

【Unity】ARKit超入門記事まとめ

ARKitは、Appleが2017年にリリースしたARフレームワークです。当時のARKit 1.0では平面認識しか出来ませんでしたが、ARKit 1.5を経て2018年にリリースされたARKit 2.0では環境マッピングの採用や複数人でのAR共有など、利用できる機能がどんどん増えてきています。

f:id:nn_hokuson:20181127200451j:plain

ARKit 1.0の頃はとても機能がすくなかったので、簡単に学習できました。でもARKit 2.0になると多くの機能が追加され、ARKitを始めるハードルが少し高くなってきました。そこで、この記事ではこれからARKitを使い始める人のために、UnityでARKitを使う方法を紹介します。

UnityでARKitを使うための準備

Unityを使ってARKitを始めるには「ARKit Plugin」というプラグインが必要になります。そのプラグインのダウンロード方法とセットアップのための入門記事です。

  • Unityで始めるARKit入門 セットアップ編 - おもちゃラボ

  • ARKitで作るモグラたたき(全3回)

    UnityとARKitを使ってARモグラたたきを作る方法をワンステップずつチュートリアル形式で紹介しています。

  • ARKitで作るARモグラ叩き その1
  • ARKitで作るARモグラ叩き その2
  • ARKitで作るARモグラ叩き その3

  • Unityで利用できるARKitの機能紹介

    ARKit2.0では環境マップや複数人でのAR共有、ARの永続化など、たくさんの機能が用意されています。ここでは、Unityから使えるARKitの機能の使い方をまとめています。

  • 3Dモデルを配置する
  • 光源推定をする
  • 平面を描画する
  • 画像トラッキングをする
  • 影を表示する
  • ARKit Remoteを使ってみる
  • 環境マッピングをしてみる
  • 水平面か垂直面かを調べる
  • GPSで特定の場所にARを表示する
  • 3Dオブジェクトをマーカーにする
  • ARでAmbient Occlusionを使う

  • 参考書籍

    ここではARKitをUnityから使う方法を紹介しました。
    ただ、ARKitの実験するだけならUnityよりもSwift+Xcodeのほうが
    実験しやすいかもしれません。

    Swiftでやってみたいけど、あんまり触ったことなくて・・・って人のために!!
    「SwiftでつくるARKit超入門」を執筆しました!
    128ページ、2000円です。BOOTHで絶賛発売中です!

    booth.pm

    書籍の内容はこちらでも紹介しています。
    参考にしてみて下さい。
    nn-hokuson.hatenablog.com

    【Unity】ARKitで作るARモグラ叩き その3

    前回はARのモグラが穴から出てくるところまでを作りました。最終回はモグラをタップで叩けるようにします。また、叩いたときのエフェクトも表示したり、アニメーションを追加したりします。

    f:id:nn_hokuson:20181101195657j:plain

    前回までの記事はこちらです。

  • ARKitで作るARモグラ叩き その1
  • ARKitで作るARモグラ叩き その2
  • ARKitで作るARモグラ叩き その3
     
    今回もUnityとARKit Pluginを使ってすすめていきます。
    拙書「ARKit超入門」もよろしくお願いします!

    モグラを叩けるようにする

    ARモグラ叩きなのでモグラをタップで叩けるようにしましょう。MoleControllerに次のHitメソッドを追加してください。

        public void Hit()
        {
            this.time = 0;
            Down();
        }
    

    ここではモグラを叩いたときに呼び出すHitメソッドを追加しました。Hitメソッドの中ではDownメソッドを呼んでいます。これにより、叩かれたら、モグラが地中に戻ります。

    次にモグラを叩く側のプログラムを作っていきますが、その前にモグラに「Mole」というタグを設定しておきます。これは叩いたオブジェクトがモグラかどうかを判別するのに使います。

    インスペクタのTagのドロップダウンを開き、Add Tagをクリックします。
    f:id:nn_hokuson:20181105231132p:plain:w300

    次に「+ボタン」をクリックして「Mole」というタグを追加します。
    f:id:nn_hokuson:20181105231211p:plain:w300

    プロジェクトウインドウでmolePrefabを選択して、Tagの欄に今作成した「Moleタグ」を設定して下さい。
    f:id:nn_hokuson:20181105231241p:plain:w300

    モグラをタッチで叩くスクリプトを作成します。プロジェクトウィンドウにHammer.csを作成して、次のスクリプトを入力してください。

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class Hammer : MonoBehaviour 
    {
    	void Update () 
        {
            if (Input.GetMouseButtonDown(0))
    		{
    			Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                RaycastHit hit = new RaycastHit();
                if(Physics.Raycast(ray, out hit))
                {
                    if(hit.transform.gameObject.CompareTag("Mole"))
                    {
                        hit.transform.gameObject.GetComponent<MoleController>().Hit();
                    }
                }
    		}
    	}
    }
    

    ScreenPointToRayメソッドを使って、タップしたところからRayを飛ばしています。そのRayがコライダと衝突するかをPhysics.Raycastメソッドで調べます。衝突したオブジェクトのTagを見て、モグラだった場合はMoleControllerのHitメソッドを呼び出しています。

    スクリプトが出来たら、これもGameオブジェクトドラッグ&ドロップしてアタッチしておきましょう。

    f:id:nn_hokuson:20181105231423j:plain

    これでモグラを叩いたら、叩かれたモグラが地中に戻るようになりました。実機にインストールして試してみてください。

    得点を表示する

    次にモグラを何匹叩いたのかを表示するUIを作ります。ヒエラルキーウインドウから「Create」→「UI」→「Text」を選択してください。

    ヒエラルキーウインドウにCanvasオブジェクトと、その子要素にTextが追加されます。Textの名前はScoreに名称変更します。

    f:id:nn_hokuson:20181105231505p:plain:w250

    実機の画面サイズによらずに、一定の大きさでUIが表示されるようにします。 ヒエラルキーウインドウでCanvasを選択して下さい。インスペクタからCanvas Scalerを探して、「UI Scale Mode」を「Scale With Screen Size」に設定し、「Screen Match Mode」を「Expand」に設定します。

    f:id:nn_hokuson:20181105231553p:plain:w300

    次にスコアの見た目の調節を行います。Textを画面上部に移動して、Anchorの場所をTopCenterに設定します。

    f:id:nn_hokuson:20181105231722j:plain:w600

    また、TextのfontやAlignment、Colorなど各種パラメータを設定します。今回は次のように設定しましたが、ここは好みに応じて変更して下さい。

    f:id:nn_hokuson:20181105231809p:plain:w300

    スクリプトから得点のUIを更新します。先ほど作成したHammerスクリプトを次のように修正してください。

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class Hammer : MonoBehaviour 
    {
        int count = 0;
    
    	void Update () 
        {
            if (Input.GetMouseButtonDown(0))
    		{
    			Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
                RaycastHit hit = new RaycastHit();
                if(Physics.Raycast(ray, out hit))
                {
                    if(hit.transform.gameObject.CompareTag("Mole"))
                    {
                        hit.transform.gameObject.GetComponent<MoleController>().Hit();
    
                        count++;
    
                        GameObject.Find("Score").GetComponent<Text>().text
                                 = "Score: " + count.ToString();
                    }
                }
    		}
    	}
    }
    

    モグラを叩いた数を数えるために、count変数を追加しています。モグラを叩いた場合はcountをインクリメントします。そのあと、Findメソッドを使ってシーンから「Score」という名前のオブジェクト(先ほど追加したText)を探して、そこにcount変数の値を表示しています。

    実行すると、叩いたモグラの数に応じてスコアが増えていくのが分かります。

    f:id:nn_hokuson:20181106191331j:plain:w480

    パーティクルを出す

    いまのままではモグラを叩いたときの反応が少し薄いです。叩いたタイミングでパーティクルを表示しましょう。今回は次のような感じの破砕エフェクトを作ります。

    f:id:nn_hokuson:20181106192102g:plain

    ヒエラルキーウインドウから「Create」→「Effect」→「Particle」を選択してください。今回は中心から円形に飛び散るようなエフェクトを作ります。

    まずは基本のパラメータを次のように設定します。
    f:id:nn_hokuson:20181105231844p:plain:w340

    パーティクルの放出形状は半球形、放出量はBurstで50に設定しました。
    f:id:nn_hokuson:20181105231909p:plain:w340

    飛び散ったパーティクルは小さくなるようにSize over Lifetimeのグラフを減衰系に設定します。
    f:id:nn_hokuson:20181105232012p:plain:w340

    最後に飛び出すパーティクルの形を立方体にするため、「Render Mode」を「Mesh」に設定し、「Mesh」は「Cube」を選択します。
    f:id:nn_hokuson:20181105232100p:plain:w340

    最後にこのパーティクルをPrefab化します。ヒエラルキーウインドウのParticle Systemをプロジェクトウィンドウにドラッグして、名前をEffectPrefabに変更して下さい。

    f:id:nn_hokuson:20181105232209j:plain:w600

    モグラを叩いたときにこのエフェクトを表示するように、MoleController.csに追記します。ここでは差分のプログラムだけ書きます。

    先頭で今作成したPrefabを格納するための変数を作ります。

        public GameObject effect;
    

    Hitメソッドの中にパーティクルを生成するプログラムを追加します。

        public void Hit()
        {
            GameObject g = Instantiate(effect, transform.position+new Vector3(0, 0.04f, 0), effect.transform.rotation);
            Destroy(g, 1.0f);
    
            this.time = 0;        
    
            Down();
        }
    

    Hitメソッドは叩かれたときに呼び出されるのでした。なので、モグラを叩いたタイミングで、その叩いたモグラの位置にパーティクルが生成されます。

    最後に、上で宣言したeffect変数にEffectPrefabの実体を代入します。プロジェクトウインドウでmolePrefabを選択して、MoleControllerのeffectの欄に「EffectPrefab」を設定します。

    f:id:nn_hokuson:20181105232454j:plain:w600

    これでモグラを叩いたときにエフェクトが表示されるようになります。

    モグラをアニメーションで動かす

    今のままではモグラが上下に瞬間移動しているので、見た目に気持ちよくありません。なめらかに移動するように修正します。UnityにはDoTweenというアニメーションのためのアセットがあるので、これを使います。

    次のURLからDoTweenをダウンロードして、プロジェクトにインポートしましょう。

    次のようなウインドウが表示されるのでSetup DoTweenをクリックして次の画面でApplyを押します(Applyボタンが押せるようになるまで時間が少しかかります)

    f:id:nn_hokuson:20181105232545j:plain:w250 f:id:nn_hokuson:20181105232558p:plain:w250

    これでセットアップは完了です。あとはモグラを動かすスクリプト(MoleController.cs)を少し修正します。DoTweenを使うためにDG.Tweeningをインポートします。

    using DG.Tweening;
    

    また、UpメソッドとDownメソッドを次のように書き換えて下さい。

    void Up()
    {
        transform.DOMoveY(groundLevel.y, 0.5f);
        this.isOnGround = true;
    }
    
    void Down()
    {
        transform.DOMoveY(undergroundLevel.y, 0.5f);
        this.isOnGround = false;
    }
    

    DoMoveYメソッドは第一引数に指定したy座標までアニメーションしながら移動します。移動時間は第二引数で指定します。これでARのモグラがなめらかに動くようになりました。

    完成

    これで無事ARモグラ叩きが完成しました。お疲れ様でした!!

    f:id:nn_hokuson:20181025200107g:plain:w450

    実際に手を動かして作ってみていかがでしたでしょうか。UnityとARKitを使えば、簡単にARのアプリケーションが作れることを体験出来たのではないかと思います。

    参考書

    ARKitの使い方をSwiftで学びたい方はコチラがおすすめです!
    booth.pm

    Unityの基本的な使い方からC#の文法、ゲームの作り方まで解説しています!

  • 【Unity】ARKitで作るARモグラ叩き その2

    前回は画面をタップしたところに穴を表示するプログラムを作りました。今回はARのモグラを生成して上下するようにするところまでを作ります。完成イメージはこんな感じです。

    f:id:nn_hokuson:20181101195113j:plain

    関連記事はこちらです。前回はタッチしたところにARで穴を表示するところまでを解説しています。

  • ARKitで作るARモグラ叩き その1
  • ARKitで作るARモグラ叩き その2
  • ARKitで作るARモグラ叩き その3


    今回もUnityとARKit Pluginを使ってすすめていきます。
    手前味噌ですが・・・Swiftを使ってARKitを学びたい方はこちらの書籍がオススメです


    モグラのPrefabを作る

    まずはプロジェクトウィンドウからシーンビューにmoleをドラッグします。そのmoleにmoletexをアタッチしてテクスチャを設定しましょう。

    f:id:nn_hokuson:20181031221451j:plain:w500

    今回もモグラのテカリが気になる方は、moletexマテリアルのインスペクタからSmoothnessを「0」に設定してください。

    f:id:nn_hokuson:20181031221607p:plain:w320

    次にモグラを叩いたときの判定をするために、コライダをアタッチしておきます。ヒエラルキーウインドウでmoleを選択した状態で、インスペクタの「Add Component」から「Capsule Collider」を選択してください。

    f:id:nn_hokuson:20181031221622p:plain:w500

    Capsule Colliderがモグラにフィットするようにパラメータを次のように調節してください。

    f:id:nn_hokuson:20181031221640p:plain:w320

    ここまでで、一旦モグラのPrefabを作っておきましょう。ヒエラルキーウインドウからプロジェクトウィンドウにmoleをドラッグ&ドロップしてください。ファイル名はmolePrefabに変更しておきます。

    f:id:nn_hokuson:20181031222020j:plain

    ヒエラルキーウインドウにあるモグラは「右クリック」→「Delete」で消しておきます。

    穴の場所にモグラを生成する

    今作成したモグラのPrefabを穴の位置に生成するスクリプトを作ります。

    プロジェクトウィンドウのHolePlacerスクリプトに、GenerateMolesメソッドとその呼び出し部分のプログラムを追加してください。

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.XR.iOS;
    
    public class HolePlacer : MonoBehaviour
    {
        bool isGenerated = false;
        public GameObject holesPrefab;
        public GameObject molePrefab;
    
        public void GenerateMoles(GameObject holes)
        {
            foreach (Transform t in holes.transform)
            {
                GameObject child = t.gameObject;
                if(child.tag == "Hole")
                {
                    Vector3 pos = child.transform.position;
                    Instantiate(molePrefab, pos, molePrefab.transform.rotation);
                }
            }
        }
        
        void HitTest(ARPoint point)
        {
            List<ARHitTestResult> hitResults = UnityARSessionNativeInterface
                .GetARSessionNativeInterface()
                .HitTest(point, ARHitTestResultType.ARHitTestResultTypeExistingPlaneUsingExtent);
    
            // 平面とあたっていた場合
            if (hitResults.Count > 0)
            {
                // 穴を生成する
                GameObject holes = Instantiate(holesPrefab);
                holes.transform.position = UnityARMatrixOps.GetPosition(hitResults[0].worldTransform);
                holes.transform.rotation = UnityARMatrixOps.GetRotation(hitResults[0].worldTransform);
    
                // モグラを生成する
                GenerateMoles(holes);
                
                this.isGenerated = true;
            }            
        }
    
        // Update is called once per frame
        void Update()
        {
            if (!isGenerated && 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);
                }
            }
        }
    }
    

    前回のプログラムにGenerateMolesメソッドを追加しています。このメソッドは引数に穴(3つの穴を子要素にもつオブジェクト)のオブジェクトを受け取ります。その子要素を調べて「Hole」というタグを持っていれば、その位置にモグラを生成しています。また、HitTestメソッドの中でこのGenerateMolesメソッドを呼び出しています。

    プログラムが追加できたら、GameオブジェクトにアタッチしたHolePlacerスクリプトのMole Prefabの欄にmolePrefabの実体をセットしてください。

    f:id:nn_hokuson:20181031222311j:plain

    ここまでで実行してみましょう。画面をタップすると穴が配置され、その上にモグラが表示されるかを確かめてください。

    f:id:nn_hokuson:20181101195727j:plain:w500

    モグラを動かす

    次にモグラが穴から出たり入ったりするようにしましょう。MoleControllerというスクリプトを作成して、次のプログラムを入力して下さい。

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class MoleController : MonoBehaviour {
    
        Vector3 groundLevel;
        Vector3 undergroundLevel;
        public GameObject effect;
    
        bool isOnGround = true;
        float time = 0;
    
        void Up()
        {
            transform.position = groundLevel;
            this.isOnGround = true;
        }
    
        void Down()
        {
            transform.position = this.undergroundLevel;
            this.isOnGround = false;
        }
    
        void Start () 
        {
            this.groundLevel = transform.position;
            this.undergroundLevel = this.groundLevel - new Vector3(0, 0.2f, 0);
    
            // 地中に隠す
            Down();
    	}
    	
    	void Update () 
        {
            this.time += Time.deltaTime;
    
            if( this.time > 2.0f )
            {
                this.time = 0;
                if( this.isOnGround) 
                {
                    Down();
                }
                else 
                {
                    Up();
                }
            }
        }
    }
    

    このスクリプトでは、time変数を使って時間をカウントして、2秒ごとにモグラを上下させています。プログラムの分かりやすさを優先して、ここではアニメーションの設定はまだしていません。なのでモグラは地上と地中の間を瞬間移動します。次の記事でDOTweenを使ったアニメーションの方法を紹介します。

    作成したMoleControllerスクリプトをモグラのPrefabにドラッグ&ドロップしてアタッチします。

    f:id:nn_hokuson:20181031222631p:plain

    実機にインストールして、モグラが上下するか確認してみましょう。

    f:id:nn_hokuson:20181101200047g:plain:w500

    モグラは上下していますが、穴の下にいるモグラまで見えてしまっていますね。これはARKitが現実世界にあるものとARオブジェクトの前後関係を認識できないのが原因です。この地中のモグラが見えてしまう対策をしていきます。

    オクルージョン対策

    現実世界にあるものとの前後関係がわからない問題は、昔からARにはつきものの問題です。ARKitではカメラ映像の上にARオブジェクトを強制的にべた書きするため、このように前後関係が崩れてしまいます。

    Depthカメラを使えば、画像の奥行きがわかるため、多少の前後判別はできるようになります。ただ、現状ではリアルタイムで計算するにはコストが高く、根本的に解決されたわけではありません。

    そこでARKitを使ってオクルージョンを実現するには手動で、オクルージョン用の平面を設定する必要があります。この平面を設定することで、それよりも奥にあるオブジェクトは描画されなくなります。

    f:id:nn_hokuson:20181101202430p:plain:w550

    まずはヒエラルキーウインドウで「Create」→「3D Object」→「Plane」を選択して穴の真下に設定します。
    また、今作成した平面をHolesの子要素にしておきます。

    f:id:nn_hokuson:20181031222809j:plain:w600

    次に平面にオクルージョン用のマテリアルを設定します。UnityARKitPlugin/Common/MaterialsにあるocclusionPlaneMaterialを平面にドラッグしてください。これにより、この平面より下にあるオブジェクトは描画されないようになります。

    f:id:nn_hokuson:20181031223100j:plain:w500

    HolesPrefabにも変更を反映するため、ヒエラルキーウインドウでHolesを選んでからインスペクタの「Apply」ボタンを押してください。

    f:id:nn_hokuson:20181031223158p:plain:w320

    オクルージョンに使ったシェーダを少しだけ見ておきましょう。UnityARKitPlugin/Example/Common/Shaders/MobileOcclusion.shaderです。ポイントは次の3行です。

    ZWrite On
    ZTest LEqual
    ColorMask 0
    

    ZWriteをOnにしてデプステストは行いつつ、ColorMaskに0を設定することで描画は行わないようにしています。つまりデプステスト的にはそこにオブジェクトがあるけど、見た目にはなにもないというおばけ状態ですね(笑)
     
     
    f:id:nn_hokuson:20181101202845p:plain:w600
     
    これにより背後のオブジェクトがデプステストにかかって描画されなくなります。シェーダについては次の記事を参照下さい。

    nn-hokuson.hatenablog.com

    実行してみる

    オクルージョン用の平面を使用したことで、穴の下にいるモグラは描画されなくなりました。

    f:id:nn_hokuson:20181101200103g:plain:w500

    今回はココまでにしましょう。次回は最終回です。最後の仕上げにモグラのアニメーションとパーティクルの発生、GUIの設定などをしていきますよ!

    nn-hokuson.hatenablog.com

    参考書

    ARKitの使い方をSwiftで学びたい方はコチラがおすすめです!
    booth.pm

    Unityの基本的な使い方からC#の文法、ゲームの作り方まで解説しています!