ポケモンGOなどで使われているAR技術について学んでみよう!(第3回開発編その2)

VR/AR

ポケモンGOなどで使われているAR技術について学んでみよう!(第3回開発編その2)

みなさん、こんにちは。
中村忍です。

前回の記事(第3回開発編その1)では、AR開発の前座として、Android OS 環境での開発環境の構築方法とテストアプリケーションを作成する方法について紹介しました。

今回の記事では、スマートフォンのGPS機能を使って周囲に2次元画像を表示するようなロケーションベース型ARを、AR開発支援ツール「Wikitude」の下で開発する方法について紹介します。


Wikitude SDKのアーキテクチャはこうなっている!

Wikitudeは、ドイツにある会社で、モバイル用のAR技術をSDK(Software Development Kit)という形で提供しています。Wikitude によると、

’Wikitude SDKは、AR体験を開発するモバイルアプリケーション用のソフトウェアライブラリおよびフレームワークです。GPSなどから取得できる位置情報を活用して現実世界を拡張するロケーションベース型ARと、画像認識をトリガーとして現実世界を拡張する画像認識型ARをサポートしています。

とあり、このSDKを使うことでポケモンGOのようなアプリケーションの開発などができます。
Wikitudeへの開発者の登録数は100,000を越え、また、Wikitude SDKを使ったアプリケーションのダウンロード数は10億を超えているそうです。

Wikitude SDKのアーキテクチャは次のようになっています。


引用:Wikitude SDK Android バージョン: 8.0.0 JavaScript API

Wikitude SDKは、他のSDKのようなAndroidまたはiOSなどのネイティブ(各OSのアプリ専用)ではありません。

Wikitude SDKでは、ARアプリケーションを、HTML、JavaScript、CSSを使ってコーディングしていきます。この部分は、iOSやAndroid OSなどのプラットフォーム非依存の記述であり、「Architect World」と呼ばれます。図では、「JS API」と書かれているレイヤーに当たります。

Architect Worldは、「Architect View」と呼ばれるビューコンポネントを経由して読み込まれます。この部分はプラットフォーム固有の機能であり、AndroidではJavaを、iOSではObjective C++を使用します。図では、「Native API」のレイヤーに当たります。

Wikitude SDKを使ってロケーションベース型ARのサンプルアプリケーションを動かしてみよう!

ARを開発するに当たって、まずは何からやっていいのかわからないのではないでしょうかか。どのソフトウェア開発にも共通して言えることだと思いますが、一番はサンプルアプリケーションをビルドして実行してみることだと思います。

Wikitude SDKでもサンプルを提供しており、この記事の参考にある「Wikitude SDK Android バージョン8.0.0 セットアップガイド」の「GitHub」という箇所から、「wikitude-sdk-samples-master」というサンプル集をダウンロードできます。

ここからは、ポケモンGOのようなロケーションベース型ARのサンプルである「07_3dModels_6_3dModelAtGeoLocation」を、前回の記事で作成したテストアプリケーションに組み込む方法を紹介していきます。

手順1.トライアルライセンスキーを入手する

WikitudeのHPより、SDKのトライアルキーをダウンロードします。SDKを使ったアプリケーションを実行するには、トライアルまたは有料版のキーが必要になります。

トライアルライセンスでは、すべての機能を使って開発と実行ができます。ただし、完成したアプリケーションでは、画面が「trial」の文字で埋め尽くされますので、配布する場合は有料版ライセンスを購入する必要がります。

キーは、「sdk-key_0.txt」というファイルとしてダウンロードされます。

手順2.前回作成のテストアプリケーションをAndroid Studioから起動する

前回作成したテストアプリケーション「Test20180309」を起動します。

手順3.プロジェクトの設定をする

筆者が所有しているAndroid OS (ver 4.4)を元に、プロジェクトの設定をします。

まず、左上の「Project」から「App」を右クリックして、「Open Module Settings」をクリックします。

「Project Structure」の画面がでるので、「App」→「Properties」より、「Compile SDK Version」を「API 26 Android 8.0(Oreo)」にします(API 19だと、Java関連のエラーが出るため)。

「Flavors」の「Min Sdk Version」と「Target Sdk Version」は、テストアプリケーション同様の「API 19 Android 4.4(KitKat)」のままで構いません。

次に、build.graleを修正し、Wikitude SDKを依存関係に入れます。
build.graleはビルド環境を記述したファイルで、いわゆるMakefileのような位置付けです。

build.graleは、テストアプリケーション直下と、app直下の2つ存在しますが、app直下の方を変更します(※build.grale は app\build.gradleに書くこと! URL:http://yukimura1227.blog.fc2.com/blog-entry-75.html )。

    dependencies
    {  
        implementation fileTree(dir: 'libs', include: ['*.jar'])
        implementation (name: 'wikitudesdk', ext:'aar')
        implementation 'com.android.support:appcompat-v7:21.0.3'
        implementation 'com.google.ar:core:1.1.0'
    }   
    repositories {
	    flatDir{
	        dirs 'libs'
	    }
	}

手順4.マニフェストファイルにAndroidのGPSやカメラ機能へのアクセスを許可する設定を入れる

以下のように、GPSやカメラなどへのアクセス権限を、app\src\main\AndroidManifest.xmlにあるマニフェストファイルのタグ内に入れます。
「ACCESS_GPS」、「CAMERA」が該当します。(赤字で記載している箇所)

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_GPS" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-feature android:name="android.hardware.camera" android:required="true" />
    <uses-feature android:name="android.hardware.location" android:required="true" />
    <uses-feature android:name="android.hardware.sensor.accelerometer" android:required="true" />
    <uses-feature android:name="android.hardware.sensor.compass" android:required="true" />
    <uses-feature android:glEsVersion="0x00020000" android:required="true" />

同じく、screenSize|orientationを、タグのプロパティに設定します。

    <activity android:name=".MainActivity" android:configChanges="screenSize|orientation">

手順5:Wikitude SDK本体を配置する

SDK「wikitudesdk.aar」を、app\libsにコピーします。
wikitudesdk.aarは、ダウンロードした「Wikitude_SDK\wikitude-sdk-android-XXX\Library」にあります。

手順6:ロケーションベース型ARサンプルアプリの配置

githubからダウンロードした、ロケーションベース型ARのサンプルアプリケーション「07_3dModels_6_3dModelAtGeoLocation」を、app\src\main\assetsフォルダにコピーします。assetsフォルダはWindowsのファイルエクスプローラーなどで作成します。

作成後、Android Studioを見ると、assets以下が自動的に同期されていることがわかると思います。
「07_3dModels_6_3dModelAtGeoLocation」を配置することにより、Architect Worldが作成されたことになりました。

手順7:WikitudeのARコンテンツを表示するためのレイアウトを定義する

app\res\layout\activity_main.xmlを修正して、WikitudeのARコンテンツを表示するためのレイアウトを定義します。
以下を、タグ内に配置します。

  <com.wikitude.architect.ArchitectView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:id="@+id/architectView" />

android:idの「architectView」は、後程、プラットフォーム依存部であるjavaファイルからレイアウトビューを読み込むために使われます。

手順8:ライセンスを読み込むためのjavaファイルを新規に作成

手順1で作成したライセンスキーを読み込むために、新しくjavaファイルを作成します。
Android Studio の左上の「Project」ペインにある、「app\src\main\java\com.example.usrname.test20180309」を右クリックし、「New」 → 「Java Class」から、「WikitudeSDKConstants.java」という名前のファイルを新規作成します(※usrnameはお使いのAndroid Studioに記載のユーザー名です)。

作成後のファイルに以下を入れて、手順1のトライアルキーを張り付けます。

  package com.example.usrname.test20180309;

  public class WikitudeSDKConstants {
      protected static final String WIKITUDE_SDK_KEY = "手順1のトライアルキー";
  }

手順9:ArchitectViewからArchitectWorldを読み込む

app\src\main\java\com\example\usrname\test20180309\MainActivity.javaを以下のように修正し、ArchitectWorldを表しているビューとindex.htmlを読み込みます。
主な説明は、ソースコードに記載しています。

	package com.example.usrname.test20180309;
	import android.support.v7.app.AppCompatActivity;
	import android.os.Bundle;
	import android.widget.TextView;

	import android.widget.Toast;
	import com.wikitude.architect.ArchitectView;
	import com.wikitude.architect.ArchitectStartupConfiguration; // Wikitude SDK 8.0.0では、StartupConfigurationではなくArchitectStartupConfigurationを使用する。
	import com.wikitude.common.camera.CameraSettings; // Wikitude SDK 8.0.0では、CameraSettingsモジュールを利用する。
	import java.io.IOException;

	import android.util.Log; // デバッグなどでログを出力する場合は、importする。

	public class MainActivity extends AppCompatActivity {
	    protected ArchitectView                architectView;	// ArchitectViewを定義する。

	    @Override
	    protected void onCreate(Bundle savedInstanceState) {
	        super.onCreate(savedInstanceState);
	        setContentView(R.layout.activity_main); // 手順7で定義したレイアウトビューactivity_main.xmlをセットする

	        this.architectView = (ArchitectView)this.findViewById( R.id.architectView ); // 手順7で定義したactivity_main.xmlに記載のレイアウトを、findViewById関数によってキー「architectView」から取得する

	        // StartupConfigrationからArchitectStartupConfigurationに変更(ver 8.0.0より)
	        final ArchitectStartupConfiguration config = new ArchitectStartupConfiguration();
	        config.setLicenseKey(this.getWikitudeSDKLicenseKey()); // ライセンスキーをセットする
	        config.setFeatures(ArchitectStartupConfiguration.Features.Geo);  // ロケーションベース型ARなのでGeoを設定する
	        config.setCameraPosition(this.getCameraPosition()); // スマートフォンのカメラの位置をGPSから読み込んでセットする

	        try {
	            this.architectView.onCreate( config ); // 上記設定を元にarchitectViewを作成する
	        } catch (RuntimeException ex)
	        {
	            this.architectView = null;
	            Toast.makeText(getApplicationContext(), "can't create Architect View", Toast.LENGTH_SHORT).show();
	        }
	    }

	    @Override // Create関数の後に呼ばれるルーチン。AppCompatActivityのをオーバーライドする。
	    protected void onPostCreate( final Bundle savedInstanceState ) {
	        super.onPostCreate(savedInstanceState);

	        if ( this.architectView != null ) {
	            // call mandatory live-cycle method of architectView
	            this.architectView.onPostCreate();
	            try {
	                this.architectView.load( this.getARchitectWorldPath() ); // asestsのArchitectWorld/index.htmlを読み込む
	                this.architectView.setCullingDistance(50 * 1000); // 50km以上の距離にあるもの全てを様々な計算の対象外とする
	            } catch (IOException ex) {
	                ex.printStackTrace();
	            }
	        }
	    }

	    @Override // 更新ルーチン。AppCompatActivityのをオーバーライドする。
	    protected void onResume() {
	        super.onResume();
	        if ( this.architectView != null ) {
	            this.architectView.onResume();
	        }
	    }

	    @Override // 一時停止ルーチン。AppCompatActivityのをオーバーライドする。
	    protected void onPause() {
	        super.onPause();
	        if ( this.architectView != null ) {
	            this.architectView.onPause();
	        }
	    }

	    @Override // 終了ルーチン。AppCompatActivityのをオーバーライドする。
	    protected void onDestroy() {
	        super.onDestroy();

	        // call mandatory live-cycle method of architectView
	        if ( this.architectView != null ) {
	            this.architectView.onDestroy();
	        }
	    }

	    // 手順8で定義したライセンスキーを返す
	    protected String getWikitudeSDKLicenseKey() {
	        return WikitudeSDKConstants.WIKITUDE_SDK_KEY;
	    }

	    // 手順6の07_3dModels_6_3dModelAtGeoLocationサンプルのassetsのindex.htmlを返す
	    protected String getARchitectWorldPath() {
	        return "ArchitectWorld/index.html";
	    }

	    // 画面を見ながらかざすARアプリにしたい場合はBACKを指定する
	    protected CameraSettings.CameraPosition getCameraPosition() {
	        return CameraSettings.CameraPosition.BACK; 
	    }
	}

手順10:ビルドする

Android Studioの上にあるメニューの「Build」→「Make Project」でビルドします。
成功すると、app\build\outputs\apk\debugに「app-debug.apk」というapkファイルが出来上がります。

apkファイルをgoogleドライブなどに保存し、Androidスマートフォンからダブルクリックすると、ダウンロードを促されます。
ダウンロードしたら、以下のようなインストール画面が表示されます。

インストール完了後、以下のようにWikitudeの画面になります。

しばらくするとカメラ画面になりますので、スマートフォンを北に5m、高さ2mの位置にかざすと、地球の2D画像が表れます。

サンプルassetであるindex.htmlでは、3dmodelatgeolocation.jsを読み込んでいます。これはjavascriptファイルであり、ARアプリケーションの入り口となります。
どんなことができるかは、参考の「Wikitude SDK APIリファレンス(クラス)」をご覧ください。
3dmodelatgeolocation.jsでは、以下のようになっています。

  • var location = new AR.RelativeLocation(null, 5, 0, 2) で、手元のスマートフォンから北5m、高度2mを指定。
  • var modelEarth = new AR.Model(
    “assets/earth.wt3”,
    { onLoaded: this.worldLoaded, scale: {x: 1,y: 1,z: 1}}
    );
    で、地球モデルを読み込み。
  • var indicatorImage = new AR.ImageResource(“assets/indi.png”);
    var indicatorDrawable = new AR.ImageDrawable(indicatorImage, 0.1, {
    verticalAnchor: AR.CONST.VERTICAL_ANCHOR.TOP
    });

    で、地球モデルを示すインジェクション画像を表示(矢印画像)。

  • var obj = new AR.GeoObject(location, {
    drawables: {
    cam: [modelEarth],
    indicator: [indicatorDrawable]
    }
    });
    で、指定したlocationにmodelEarthを表示。インジケーターとして、indicatorDrawableを表示。

まとめ

今週の記事で、ポケモンGOのようなロケーションベース型ARのアプリケーション作成の土台ができました。あとは、javascriptファイルを元にコンテンツを充実させるだけとなります。

今回は地球オブジェクトを表示しましたが、Wikitudeでは一般的に使用される「.fbx形式」のモデルデータを「.wt3」というWikitude専用のモデルデータに変換することができます。例えば、ドラゴンのモデルデータを地球の代わりにすれば、あたかもドラゴンが飛んでいるかのように表現することができます。

ポケモンGOでは、サーバーと通信しながら、スマートフォンが特定の位置に来たらキャラクターを表示しますが、さらに空間認識によって、机などの上にピッタリと、まるで本当にその場にいるかのように表示しています。

この記事を元に、オリジナルのロケーションベース型のARを作成してみてはいかがでしょうか。
※記事で載せたコードのビルド&実行に関しては、自己責任でお願いします。

参考