Developer's Blog

次世代の AR を体験! Tango をはじめよう

アプリケーション共同開発部 の石丸です。
Android エンジニアをやっています。

昨年は VR 関連製品が多く発売され、大きな話題となりましたが、今年は AR 関連の製品やサービスが増えてくるのではないかと考えています。

中でも私個人が注目しているのは、Googleが開発しているARプラットフォーム『Tango』で、その『Tango』に対応した端末が、昨年末ついにリリースされました。

Lenovo Phab 2 Pro


( Nexus6P (左)よりもさらに一回り大きいです)

AR(拡張現実)といえば、日本でも数年前に話題となったARカメラや、昨年社会現象にもなったポケモン GO などが有名ですが、Tango ではより一歩進んだ AR 体験が可能となります。

Tangoで何ができるのか

Tango (英語サイト)

Tango では現在以下の機能が提供されています。

  • モーショントラッキング (Motion Tracking)
  • エリア学習 (Area Learning)
  • 深度検出 (Depth Perception)

モーショントラッキングは、動きを検知し、端末の向きや移動量を取得することができます。

エリア学習は、エリアの視覚的な特徴等を記憶し、モーショントラッキングの精度を上げることができます。

深度検出は、赤外線センサーを使用し、センサーを向けている方向の物体までの距離(座標)を取得することができます。

早速試してみる

それでは、早速サンプルなどを参考に Tango 機能を試してみたいと思います。
今回はモーショントラッキングと深度検出をテストするため、画面をタップした位置に、オブジェクトを配置するサンプルを作成します。

Tango の API は、 Java 、 C 、 Unity 用のものが公開されていますが、今回は Unity 用の SDK を使用します。

検証環境

  • Unity 5.3.5 p5 (Mac)
  • Android Studio 2.2.2
  • JDK 1.8.0_91
  • Tango SDK 1.4.9

検証端末

  • Phab2 Pro (Android 6.0.1)

(環境設定等は割愛します)

Download the Tango SDK

Tango のサイトより、 Tango SDK の unity package をダウンロードし、
Assets > Import Package > Custom Package からインポートします。

新しいSceneを作成し、以下の Prefab を Hierarchy に追加します。

  • Tango/Prefabs/Manager
  • Tango/Prefabs/AR Camera
  • Tango/Prefabs/Tango Point Cloud

追加した Tango Manager の Inspector で、
以下にそれぞれチェックが入った状態にします。

  • Enable Motion Tracking
  • Enable Depth
  • Enable Video Overray

(デフォルトのカメラが残っている場合は削除しておきます)

次にサンプルなどを参考に制御用のスクリプトを書いていきます。
Tango SDK に最低限必要なメソッドが揃っている為、書く内容としてはシンプルです。

[PointTest.cs]

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Tango;

public class PointTest : MonoBehaviour, ITangoDepth {

    #region -- 公開フィールド --

    public TangoPointCloud tangoPointCloud;
    public GameObject loadResource;

    #endregion

    #region -- 非公開フィールド --

    private TangoApplication tangoApplication;
    private GameObject loadedObject = null;
    private Vector3 targetPoint = Vector3.zero;
    private bool isWaitingCallback = false;

    #endregion

    #region -- Unityライフサイクル --

    public void Start() {
        tangoApplication = FindObjectOfType<TangoApplication>();

        // リスナの登録
        tangoApplication.Register(this);
    }

    public void OnDestroy() {
        // リスナの解除
        tangoApplication.Unregister(this);
    }

    public void Update() {
        if(Input.GetMouseButtonDown(0)) {
            StartCoroutine(GetTouchPostion(Input.mousePosition));
        }
    }

    public void OnGUI() {
        // タップ地点とカメラの距離
        float dist =(targetPoint - Camera.main.transform.position).sqrMagnitude;
        GUI.Label(new Rect(40, 40, 400, 100), string.Format("<size=40>{0:f4}</size>", dist));
    }

    #endregion

    // タッチした地点にオブジェクトを配置する
    IEnumerator GetTouchPostion(Vector2 screenPos) {
        // 深度情報が取得できるまで待つ
        isWaitingCallback = true;
        tangoApplication.SetDepthCameraRate(TangoEnums.TangoDepthCameraRate.MAXIMUM);
        while(isWaitingCallback) {
            yield return null;
        }
        tangoApplication.SetDepthCameraRate(TangoEnums.TangoDepthCameraRate.DISABLED);

        // 取得した深度(点群)情報の中からタッチされた画面座標の地点に近いワールド座標を取得
        Camera cam = Camera.main;
        int index = tangoPointCloud.FindClosestPoint(cam, screenPos, 20);
        if(index >= 0) {
            SetCharactorObject(tangoPointCloud.m_points [index]);
        }
    }

    private void SetCharactorObject(Vector3 position) {
        targetPoint = position;

        if(loadedObject == null) {
            loadedObject =(GameObject)Instantiate(loadResource, targetPoint, Quaternion.identity);
        } else {
            loadedObject.transform.position = targetPoint;
        }

        // こちらを向いた状態にする
        Vector3 target = Camera.main.gameObject.transform.position;
        target.y = loadedObject.transform.position.y;

        loadedObject.transform.LookAt(target);
    }

    #region -- Tangoイベント --

    // TangoServiceへの接続
    public void OnTangoServiceConnected() {
        tangoApplication.SetDepthCameraRate(TangoEnums.TangoDepthCameraRate.DISABLED);
    }

    // TangoServiceとの切断
    public void OnTangoServiceDisconnected() {
    }

    // 深度情報が更新された
    public void OnTangoDepthAvailable(TangoUnityDepth tangoDepth) {
        isWaitingCallback = false;
    }

    #endregion
}

Hierarchy に GameObject (ここでは Test Object としています) を追加し、
そこに先ほど作成したスクリプトを追加します。

PointTest の Tango Point Could には、
先に Hierarchy に追加してある Tango Point Could を紐付けます。
Load Resource には、タッチした座標表示したいオブジェクトを任意で設定します。

表示するオブジェクトは、今回はUnity ちゃんのモデルをお借りしました。

Scene をセーブしたら、早速実行してみましょう。

画面をタップすると、タップした位置に Unity ちゃんが表示されます。
端末を持って回りこむことで、後ろからも見ることができます。

今回試したのはごくシンプルな内容ですが、今までは難しかったような機能が実現できたり、色々想像が膨らみますね!

今後、 Tango の対応端末が増え、センサーや端末の性能が向上していくと、スマホがより便利に、そして新しい使い方、楽しみ方が見えてくるように思います。

 

フェンリルのオフィシャル Twitter アカウントでは、フェンリルプロダクトの最新情報などをつぶやいています。よろしければフォローしてください!

この投稿のユニティちゃんは、以下のライセンスに従っております
© Unity Technologies Japan/UCL

Copyright © 2019 Fenrir Inc. All rights reserved.