/Test_you

電子工作やプログラミングなど、やってみたことのメモ

ARCoreを使って、ユニティちゃんを地面で歩かせてみた

ARCoreで地面(平面)を検出し、その上でユニティちゃんを歩かせてみました
※正確には、地面に配置した透明なPlaneの上を歩いています。また、Planeを外れるとユニティちゃんが落下するため、移動できる範囲は5mくらいです


~ 目次 ~


環境

  • Galaxy S8 SCV36(au) ※Android 8.0.0, ARCore V1.5.180910096 をインストール済み
  • Windows10(64bit)
  • Unity 2018.1.1f1(64-bit)
  • ARCore SDK for Unity v1.5.0
  • "Unity-chan!" Model(V1.1)

手順1. Unity-Chan!を導入して、PC上でユニティちゃんを動かす

※この作業はPC単体で行います

  • Asset Store より"Unity-Chan!" Model をインポート

  • Assets/UnityChan/Prefabs/unitychanをHierarchyに追加

  • unitychan のInspectorで下記を実施

    • Animator の Controller をUnityChanARPose からUnityChanLocomotions に変更
    • IdleChangerFaceUpdateを削除
    • スクリプトAssets/UnityChan/Scripts/UnityChanControlScriptWithRgidBodyを追加
    • Rigidbody 設定で、Constraints > Freeze Rotation の X,Y,Z にチェックを入れる
    • Capsule Collider 設定で、CenterのYを0.75、Heightを1.5 にして、ユニティちゃんの大きさに合わせる
  • メニューからGameObject > 3D Object > Plane を選択して、Planeを生成。Transform 設定で、Poisiton を (0, 0, 0) に

  • PC上で実行(Play)。カーソルキーでユニティちゃんの前後移動と旋回操作ができればOK

手順2. ARCoreを導入し、Android上でユニティちゃんを表示

※この作業はPCとAndroid端末を接続して行います

  • 下記より ARCore SDK for Unity arcore-unity-sdk-v1.5.0.unitypackage をダウンロードし、インポート
    Releases · google-ar/arcore-unity-sdk · GitHub

  • Assets/GoogleARCore/Prefabs/ARCore DeviceをHierarchyに追加し、Main Cameraを削除

  • 下記を参考に、Android および ARCore用のビルド設定をする
    ARCore 取扱説明書 - Qiita

    • Build Settings を開き、Platform をAndroid に変更(Switch Platformを忘れずに)
    • PlayerSettings を開く
      • Product Name と、Other Settings のPackage Name を設定
      • Other Settings のMultithreaded Rendering のチェックを外す
      • Other Settings のMinimum/Target API Level をAndroid 7.0 以上に設定
      • XR Settings のARCore Supported をチェック
  • Build&Runする。アプリが起動したら後ろに移動して、Planeに乗ったユニティちゃんが見えればOK

手順3. ARCoreを設定し、平面を検出できるようにする

※この作業はPCとAndroid端末を接続して行います

  • Aseetsで右クリック。Create>GoogleARCore>SessionConfig を選択

  • 生成されたARCoreSessionConfigを選択。Plane Finding Mode をHorizontal に設定
    ※今回は地面を検出したいので、水平面のみ検出するよう設定

  • Hierarchy からARCore Device を選択。AR Core Session 設定のSession Config にARCoreSessionConfigをセット

  • メニューより、GameObject>Create Empty を選択。生成されたGameObjectに、スクリプト Assets/GoogleARCore/Examples/Common/Scripts/DetectedPlaneGeneratorを追加

  • DetectedPlaneGenerator 設定のDetected Plane Prefab に、Assets/GoogleARCore/Examples/Common/Prefabs/DetectedPlaneVisualizerをセット

  • Hierarchy からPlane を選択。Mesh Renderer横のチェックを外して、Plane を透明にする
    ※最後に透明にする予定でしたが、実行時に邪魔になるので、ここで透明にしておきます

  • Build&Runする。アプリが起動したら床を見渡して、メッシュが表示されたらOK
    ※動画では赤いメッシュになってますが、通常は最初に白いメッシュが表示されます

手順4. ARCoreで検出した平面に、ユニティちゃんを配置

※この作業はPCとAndroid端末を接続して行います

  • GameObject に新規スクリプトPutUnityChan.csを追加

  • スクリプトを記述。大まかに下記を行っています

    • 画面タッチを検出
    • タッチ位置を、ARCore が検出した平面上での位置に変換
    • 平面上に、ユニティちゃんとPlane を配置
    • Anchorを設置し、ユニティちゃんとPlane をその子にする
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using GoogleARCore;

public class PutUnityChan : MonoBehaviour {

    // 平面上に配置する ユニティちゃん と Plane を指定する
    public GameObject UnityChan;
    public GameObject Plane;

    // Use this for initialization
    void Start () {
        
    }
    
    // Update is called once per frame
    void Update () {
        // タッチしていないなら、何もしない
        if (Input.touchCount < 1) return;

        // GUIに対するタッチであれば無視する
        // ※この条件は、後で追加するGUI操作を意識した物。GUIを追加しない場合は不要。
        if (EventSystem.current != null &&
            EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId)) return;

        // タッチ点の取得
        Touch touch = Input.GetTouch(0);

        // タッチの開始以外は、無視する
        if (touch.phase != TouchPhase.Began) return;

        // タッチした先に、ARCoreが検出した平面があるかチェック
        // PlaneWithinPolygon:延長線上の点が「平面を構成するポリゴン境界内」に交差する点を探す
        TrackableHit hit;
        if (Frame.Raycast(touch.position.x, touch.position.y, TrackableHitFlags.PlaneWithinPolygon, out hit))
        {
            // 平面上にオブジェクトを配置
            if (hit.Trackable is DetectedPlane)
            {
                // UnityChan の位置・姿勢を指定
                // ※hit.Pose.rotationは、Z+方向がカメラの向きになる
                //   そのままだと後ろを向いてしまうので、Y軸回りに180度回転
                UnityChan.transform.position = hit.Pose.position;
                UnityChan.transform.rotation = hit.Pose.rotation;
                UnityChan.transform.Rotate(0, 180, 0, Space.Self);

                // Plane の位置・姿勢を指定
                Plane.transform.position = hit.Pose.position;
                Plane.transform.rotation = hit.Pose.rotation;

                // Anchorを生成し、各オブジェクトをAnchorの子にする
                // ※ARCoreで位置関係を維持するには、Anchorを生成し、その子に入れる必要がある
                Anchor anchor = hit.Trackable.CreateAnchor(hit.Pose);
                UnityChan.transform.parent = anchor.transform;
                Plane.transform.parent = anchor.transform;
            }
        }
    }
}
  • PutUnityChan 設定の Unity Chan と Plane に、unitychanPlaneをセット

  • unitychan にアタッチされているスクリプトUnityChanControlScriptWithRgidBody.csを修正(2か所)

////// 1. キャラクターを移動させる(100行付近)を、ローカル座標からワールド座標に変更

        // 上下のキー入力でキャラクターを移動させる
#if false
        transform.localPosition += velocity * Time.fixedDeltaTime;
#else
        // ワールド座標系で移動するように変更
        // ※オブジェクトをAnchorの子オブジェクトとしている関係で
        //   ローカル座標系で移動させると、おかしな方向に移動してしまう。
        transform.position += velocity * Time.fixedDeltaTime;
#endif
////// 2. GUI表示(190行付近)を、コメントアウト

    void OnGUI()
    {
#if false
        // GUI表示は無効にする
        GUI.Box(new Rect(Screen.width -260, 10 ,250 ,150), "Interaction");
        GUI.Label(new Rect(Screen.width -245,30,250,30),"Up/Down Arrow : Go Forwald/Go Back");
        GUI.Label(new Rect(Screen.width -245,50,250,30),"Left/Right Arrow : Turn Left/Turn Right");
        GUI.Label(new Rect(Screen.width -245,70,250,30),"Hit Space key while Running : Jump");
        GUI.Label(new Rect(Screen.width -245,90,250,30),"Hit Spase key while Stopping : Rest");
        GUI.Label(new Rect(Screen.width -245,110,250,30),"Left Control : Front Camera");
        GUI.Label(new Rect(Screen.width -245,130,250,30),"Alt : LookAt Camera");
#endif
    }
  • Build&Runする
    • アプリが起動したら床を見渡して、メッシュを表示させる
    • メッシュ内をタップし、ユニティちゃんが表示されればOK
    • もし、ゲームパッドやキーボードが使える状態なら、ユニティちゃんを操作できます
      ※DualShock4なら左スティック(環境依存かも)、キーボードならカーソルキーで操作

手順5. GUIを追加して、ユニティちゃんを動かす

※この作業はPCとAndroid端末を接続して行います

  • メニューより、Assets > Import Package > CrossPlatformInput を選択、CrossPlatformInputをインポート

  • Assets/Standard Assets/CrossPlatformInput/Prefabs/MobileAircraftControlsをHierarchyに追加

  • MobileAircraftControls以下を修正

    • Throttle, TiltSteerInputV, TiltSteerInputH を削除
      ※ 最初の削除時に、Brake Prefab instance のメッセージが出るがContinue を押す
    • メニューより、GameObject>UI>Panel を選択し、Panel を追加。MobileAircraftControlsの一番上に配置
    • Brake を右クリックしてDuplicate(複製)を選択し、Brake(1)を作成
    • Brake の名称をWalkに変更。Brake(1)の名称をStopに変更

    ~ 修正内容の補足 ~

    • Left, Rightボタン: 左右旋回用のボタン
    • Walk, Stopボタン: 歩く、停止用のボタン
    • Panel: ボタン周辺を触ったときに画面タッチが誤動作するのを防ぐために設置
  • 各オブジェクトのInspector を修正

    • 各オブジェクトのRect Transfom 設定で、Anchorsを変更して、配置を修正
    • WalkStopのEvent Trigger 設定にて
      • ButtonHandler.SetAxisPositiveStateButtonHandler.SetDownState に変更
      • ButtonHandler.SetAxisNegativeStateButtonHandler.SetUpState に変更
    • WalkStopのButton Handler 設定にて、Name を"Walk"と"Stop"に変更
    • WalkStopの子に入っているTextの設定にて、Textを"Walk"と"Stop"に変更

    ~ 修正内容の補足 ~

    • Left, Rightボタンは、Name: "Horizontal"と設定。CrossPlatformInputManager.GetAxis("Horizontal") で、2つのボタン押下に応じた値(-1, 0, +1)を取得できる
    • Walk, Stopボタンは、Name: "Walk","Stop"と設定。それぞれのボタン押下を CrossPlatformInputManager.GetButtonDown("Walk" or "Stop")で取得できる
  • unitychan にアタッチされているスクリプトUnityChanControlScriptWithRgidBody.csを修正(3か所)

////// 1. CrossPlatformInputを使うための using ディレクティブ 追加(10行付近)

using UnityEngine;
using System.Collections;
#if true
using UnityStandardAssets.CrossPlatformInput;
#endif
////// 2. 前後移動を記憶するためのメンバ変数を追加(40行付近)

    private GameObject cameraObject;    // メインカメラへの参照

#if true
    private float vertical_ = 0.0f;     // 前後移動を記憶
#endif

    // アニメーター各ステートへの参照
    static int idleState = Animator.StringToHash("Base Layer.Idle");
////// 3. 移動操作(70行付近)で、CrossPlatformInputを使うように修正

    void FixedUpdate ()
    {
#if false
        float h = Input.GetAxis("Horizontal");  // 入力デバイスの水平軸をhで定義
        float v = Input.GetAxis("Vertical");    // 入力デバイスの垂直軸をvで定義
#else
        // CrossPlatformInputによる操作
        // 左右移動は、バーチャルパッドの水平軸([Left],[Right]ボタン操作)をそのまま反映
        float h = CrossPlatformInputManager.GetAxis("Horizontal");
        // 前後移動は、[Walk],[Stop]ボタン押下に応じて、前方移動・停止を切り替え
        if (CrossPlatformInputManager.GetButtonDown("Walk"))
        {
            vertical_ = 0.15f;
        }
        else if (CrossPlatformInputManager.GetButtonDown("Stop"))
        {
            vertical_ = 0.0f;
        }
        float v = vertical_;
#endif
  • UnityChanControlScriptWithRgidBody の設定で、移動速度を遅くする
    ※デフォルトの速度だと、操作しにくいため

    • Anim Speed: 1
    • Foward Speed: 3.5
    • Rotate Speed: 1.5
  • Build&Runする

    • アプリが起動したら床を見渡して、メッシュを表示させる
    • メッシュ内をタップすると、ユニティちゃんが表示される
    • Leftボタン, Rightボタン で、ユニティちゃんが旋回する
    • Walkボタン, Stopボタン で、ユニティちゃんの歩く・止まるを操作できればOK

    タイトルの動画へ

参考にした情報

  1. ヽ|∵|ゝ(Fantom) の 開発blog? - 【Unity】ARCore を使って現実世界にプロ生ちゃんを召喚してみる
    ⇒ こちらを見たのがきっかけで、自分でも試してみました

  2. tks_yoshinagaの日記 - ARCore対応コンテンツ開発入門
    ARコンテンツ作成勉強会資料 - はじめようArcore (修正版)
    ⇒ ARCoreの導入、検出した平面へのオブジェクト配置は、こちらの資料に従って進めました

  3. Qiita @taptappun さん - ARCore 取扱説明書
    ⇒ ARCoreの情報は、よくこちらを参照します

  4. おもちゃラボ - 【Unity】ボタンを押したときに画面クリックは無視する



この作品はユニティちゃんライセンス条項の元に提供されています