一覧に戻る

ARコンテンツを動的に読み込むロケーションベースアプリを作る

2016.12.24技術系記事

ARコンテンツをダイナミックに読み込んで表示する位置情報ARアプリの作り方です。

ARコンテンツを動的に読み込むロケーションベースアプリを作る

前回の Cordovaを使ってARアプリを体験する(位置情報編) では現在位置に基づいてARコンテンツを表示していました。しかしより本格的なARアプリではコンテンツを動的に読み込んで表示するものが殆どです。

今回は位置情報に基づいたデータをmBaaS(mobile Backend As a Service)であるニフティクラウド mobile backendに保存して動的なARコンテンツ表示を実現してみたいと思います。

ニフティクラウド mobile backendについて

ニフティクラウド mobile backendはmBaaS(mobile Backend As a Service)と呼ばれるサービスで、スマートフォンアプリ開発で必要になるバックエンド(サーバ側)処理を提供してくれるサービスです。データを保存したり、プッシュ通知や認証機能などがあります。その一つに位置情報検索機能があります。

SDKとしてJavaScript SDKがあります。これはCordovaやHTML5、Node.jsでの利用が可能です。その他、iOS/Android/Unity向けにSDKが提供されています。今回はこのJavaScript SDKを使って作ってみたいと思います。

ニフティクラウド mobile backendの使い方

簡単な使い方として、NIFTYCloud-mbaas/ncmb_js にある ncmb.min.js をダウンロードしてCordovaプロジェクトの中で読み込みます。

そして JavaScript側ではニフティクラウド mobile backendのインスタンスを作ります。この際の初期化で使っているアプリケーションキー(application_key)とクライアントキー(client_key)というのはニフティクラウド mobile backendの認証用キーで、ユーザ登録してアプリを作成すると生成されます。

var application_key = 'e6...69';
var client_key = '65...47';
var ncmb = new NCMB(application_key, client_key);

位置情報データの保存

そしてデータの保存先を作ります。これは自由に名前が決められます(その名前がなかったら自動的に作られます)。今回は WikitudeGeo としています。

var WikitudeGeo = ncmb.DataStore('WikitudeGeo');

このデータの保存先はデータベースで言うとテーブルに相当するもので、さらに行に相当するデータはこのテーブルのインスタンスになります。

var wikitudegeo = new WikitudeGeo();

さらに位置情報オブジェクトを作ります。引数は緯度、経度です。

var geoPoint = new ncmb.GeoPoint(latitude, longitude);

後はこの位置情報をデータとしてセットして保存するだけです。

wikitudegeo.set('point', geoPoint);
wikitudegeo.save() .then(function(obj) { alert('登録しました'); }) .catch(function(e) { alert(e); })

これでニフティクラウド mobile backendへのデータ保存処理が完了しました。

位置情報データの検索

次に位置情報データの検索です。これは先ほどの WikitudeGeo に対して行います。 withinKilometers というメソッドで指定した距離(今回は1km)の範囲内にあるデータを検索します。実際の処理は fetchAll メソッドにて実行されて、結果が配列で返ってきます。

WikitudeGeo.withinKilometers('point', geoPoint, 1).fetchAll().then(function(ary) {
    /* 結果が配列で返ってくる ary[0].point.latitude ary[0].point.longitude にてアクセス可能 */
});

後は同じ仕組みをアプリの中に組み込んでいきます。

位置情報を保存する

例えば index.html を次のように変更します。アプリを起動していきなりARを表示するのではなく、次のようにリンクで表示するように変更します。

<script type="text/javascript" src="js/jquery.min.js">
</script><script type="text/javascript" src="js/ncmb.min.js"></script>
<a class="open">ARを表示</a>
<a class="register">現在位置を登録</a>

現在位置を登録をタップした時には次のように処理を行います。

$('.register').on('click', function(e) { e.preventDefault();
// スマートフォンの位置情報を取得
navigator.geolocation.getCurrentPosition( function(position) {
    // 位置情報をニフティクラウド mobile backendに保存
    var geoPoint = new ncmb.GeoPoint(position.coords.latitude, position.coords.longitude);
    var WikitudeGeo = ncmb.DataStore('WikitudeGeo');
    var wikitudegeo = new WikitudeGeo();
    wikitudegeo.set('point', geoPoint);
    wikitudegeo.save().then(function(obj) { alert('登録しました'); }).catch(function(e) { alert(e); }) }, function(e) { alert(e);} , {enableHighAccuracy: true, maximumAge: 180000} );
});

先ほど説明したコードが殆どですが、スマートフォンの位置情報を取得する処理が追加されています。Webブラウザデフォルトの方法もありますし、apache/cordova-plugin-geolocation: Mirror of Apache Cordova Plugin geolocationを使っても良いでしょう。こちらの場合、アプリ側ですでに許可されているため、確認アラートが出ないのが利点です。

ARを表示をタップした時には ar.html を表示する処理を実行します。この部分は元々のコードから移動しておきます。

$('.open').on('click', function(e) { e.preventDefault(); app.wikitudePlugin.loadARchitectWorld( app.onARExperienceLoadedSuccessful, app.onARExperienceLoadError, 'www/ar.html', [ 'geo'], {'camera_position': 'back'} ); });

ARを表示する

ar.htmlでは以下のメタタグを追加します。これはCordovaアプリとしてのセキュリティ上の制限があるためです。また、ncmb.min.jsはこちらでも読み込んでおいてください。

<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: architect: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *; connect-src 'self' https://mb.api.cloud.nifty.com" >

ar.jsは次のようになります。位置情報データを検索した後、近くにあるデータに合わせてモデルデータを表示しています。今回は同じ3Dモデルを使っていますが、これはデータの中の属性に応じて変えた方が良いでしょう。

var application_key = 'e6...69';
var client_key = '65...47';
var ncmb = new NCMB(application_key, client_key);
var World = { init: function () { navigator.geolocation.getCurrentPosition( function(position) { var geoPoint = new ncmb.GeoPoint(position.coords.latitude, position.coords.longitude);
var WikitudeGeo = ncmb.DataStore('WikitudeGeo');
WikitudeGeo.withinKilometers('point', geoPoint, 1) .fetchAll() .then(function(ary) { var modelEarth = new AR.Model("assets/dragon_floating.wt3", { scale: { x: 0.001, y: 0.001, z: 0.001 }, rotate: { roll: 25, tilt: 50.0, } });
for (var i in ary) {
    var geo = ary[i];
    var location = new AR.GeoLocation(geo.point.latitude, geo.point.longitude);
    console.log(location);
    var obj = new AR.GeoObject(location, { drawables: { cam: [modelEarth], } }); } }); }); }, };
World.init();

ここまでできると、位置情報を登録をタップした場所でARコンテンツが表示されるという仕組みができあがります。アプリをインストールした人たちと位置情報を共有するゲームを作ったり、運営側で位置情報をメンテナンスしてアプリをアップデートするといった仕組みが実現できます。

なお、位置情報は取得精度によってブレがあるので同じ場所で保存したとしても描画した際には遠くにあるように表示される可能性があります。

今回のコードはmoongift/WikitudeNCMBGeoDemoにアップロードしてあります。実装で不明点があれば参考にしてください。