2020年12月22日
AR.jsでLocation Based ARを作ってみる
目次
はじめに
この記事は 新しい技術にチャレンジし続けるpalanのアドベントカレンダー 22日目の記事です。 昨日は「デザイン制作・コーディングツール「Hadron」を使ってみた」という記事でした。デザイン制作・コーディングツール「Hadron」を使ってみた今回はAR.jsのLocation Based ARを作ってみたので、その作り方や特徴を紹介します。
Location Based ARとは
Location Based AR(ロケーションベース型AR)とはGPSなどの位置情報に基づいて、特定の位置にARコンテンツを表示させるARです。例えば地図アプリのナビゲーションで目的地の方向や位置を示すのに使われてたりします。AR.jsのLocation Based AR
AR.jsのバージョン3以降ではLocation Basedに対応しています。これを使うと、わずかなコードでLocation BasedのWebARを簡単に作成できます。 AR.jsのLocation Based ARはA-Frameバージョンとthree.jsバージョンの2つがありますが、本記事ではA-frameバージョンを使用しています。 AR.js DocumentationLocation Based – AR.js Documentation
A-Frame – Make WebVR A-Frameに関しては以前の記事でも触れてるので良かったらこちらもご覧ください。
A-Frameで始めるクリエイティブ・コーディング入門
試してみる
まずは最小限のコードでLocation Based ARを作成して体験してみます。 A-FRAMEのblog記事にちょうどいいサンプルコードがありますので、こちらを試してみます。
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Location-based AR.js demo</title>
<script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script>
<script src="https://unpkg.com/aframe-look-at-component@0.8.0/dist/aframe-look-at-component.min.js"></script>
<script src="https://raw.githack.com/AR-js-org/AR.js/master/aframe/build/aframe-ar-nft.js"></script>
</head>
<body style="margin: 0; overflow: hidden;">
<a-scene
vr-mode-ui="enabled: false"
embedded
arjs="sourceType: webcam; debugUIEnabled: false;"
>
<a-text
value="This content will always face you."
look-at="[gps-camera]"
scale="50 50 50"
gps-entity-place="latitude: <add-your-latitude>; longitude: <add-your-longitude>;"
></a-text>
<a-camera gps-camera rotation-reader> </a-camera>
</a-scene>
</body>
</html>
[Image Tracking and Location-Based AR with A-Frame and AR.js 3 – A-Frameから引用
POINT!!
コードの一部を解説をします。
<script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script>
<script src="https://unpkg.com/aframe-look-at-component@0.8.0/dist/aframe-look-at-component.min.js"></script>
<script src="https://raw.githack.com/AR-js-org/AR.js/master/aframe/build/aframe-ar-nft.js"></script>
A-Frameと、AR.jsのA-FrameバージョンのJavaScriptを読み込みます。また、後述する
look-at
を使用するためのライブラリも読み込みます。
<a-camera gps-camera rotation-reader></a-camera>
GPS情報を利用するためa-camera
にgps-camera
を追加します。加えて、回転イベントを処理するために
rotation-reader
も追加します。
<a-text
value="This content will always face you."
look-at="[gps-camera]"
scale="50 50 50"
gps-entity-place="latitude: <add-your-latitude>; longitude: <add-your-longitude>;"
></a-text>
look-at
属性に[gps-camera]
を指定することで、ARコンテンツが常にカメラの方を向きます。テキストや画像などの2Dコンテンツでは基本的にこの指定を入れることをおすすめします。3Dはケースバイケースで指定してください。
ARコンテンツにはgps-entity-place
にARコンテンツを配置したい座標の緯度経度を指定します。ソースコード内の、<add-your-latitude>
に緯度<add-your-longitude>
に経度を入れます。
例(東京タワーに表示したい場合)
gps-entity-place="latitude: 35.65861027555679; longitude: 139.74542998791907;"
TIPS
Google Mapで取得したい座標で右クリックすると一番上に緯度経度が表示されます。緯度経度部分をクリックするとクリップボードにコピーされます。体験する
上記のソースコード内の<add-your-latitude>
と<add-your-longitude>
にARコンテンツを表示させたい緯度経度を指定したらサーバーにアップしてスマートフォンでアクセスします。
GPS情報取得とデバイスモーションの利用、カメラのアクセスを求められるので全て許可します。スマートフォンの画面をARコンテンツを設置した方向に向けるとARコンテンツがその位置に表示されます。 テキストのみでちょっと味気ないですが、簡単にLocation Based ARを体験できました。
AR.jsのLocation Based ARの課題
このようにAR.jsを使うと簡単にLocation BasedのWebARを作成できます。ただ、体験してもらうと分かりますが課題に感じる部分も幾つかあります。
オクルージョンされない
オクルージョンとは手前にある物体が後ろにある物体を隠して見えなくする状態のことです。AR.jsのLocation Based ARでは、カメラとARコンテンツの間に物体がある場合でも、ARの体験画面では常に全体が表示されます。(正確にはLocation Basedに限った話ではないですが)
カメラとの距離によってスケールは縮小されて表示はされるのですが、体験する側としては遠くにあるコンテンツが縮小されているのか、小さいコンテンツが目の前にあるのか判断するのは難しいです。
位置取得の精度
カメラ位置の取得にはGeoLocation APIを使用しています。そのためデバイスのGPS取得の精度に依存します。GPS取得の精度を良くするためLocation BasedのARでは屋外での使用を推奨されてますが、屋外であっても私が試してみた所感ですが、10m前後のブレはあります。
GPSの位置がブレることで画面内のARコンテンツの表示される位置も変わってきます。特にARコンテンツとの距離が近いほどそのズレは大きくなります。
Location Based ARの体験を良くする工夫
前述のような課題はありますが、設定を変えたり工夫次第で良い体験を生むことはできます。幾つか例を紹介します。
ARコンテンツを表示する最大距離、最小距離を設定する
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Location-based AR.js demo</title>
<script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script>
<script src="https://unpkg.com/aframe-look-at-component@0.8.0/dist/aframe-look-at-component.min.js"></script>
<script src="https://raw.githack.com/AR-js-org/AR.js/master/aframe/build/aframe-ar-nft.js"></script>
</head>
<body style="margin: 0; overflow: hidden;">
<a-scene
vr-mode-ui="enabled: false"
embedded
arjs="sourceType: webcam; debugUIEnabled: false;"
>
<a-box
material="color: red"
gps-entity-place="latitude: <add-your-latitude>; longitude: <add-your-longitude>;"
scale="30 30 30"
></a-box>
<a-camera gps-camera="minDistance:30; maxDistance:100" rotation-reader> </a-camera>
</a-scene>
</body>
</html>
gps-camera
にminDistance
とmaxDistance
プロパティを設定すると、ARコンテンツを表示する最大距離、最小距離を設定できます。単位はmです。
最大距離を設定した場合、その距離より離れている場合はARコンテンツを表示しません。これにより、遠く離れた位置からでもARコンテンツが表示されてしまう問題を防げます。
また、最小距離を設定した場合は、その距離より近い場合はARコンテンツを非表示にします。
例えばARコンテンツの大きさが10mのように大きい場合、その中に入ってしまった場合にうまく表示されない問題を防ぎます。 これらの設定をすることで限られたエリアにいる場合のみARコンテンツを出現させることができます。
位置情報の小さな変化を無視する
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Location-based AR.js demo</title>
<script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script>
<script src="https://unpkg.com/aframe-look-at-component@0.8.0/dist/aframe-look-at-component.min.js"></script>
<script src="https://raw.githack.com/AR-js-org/AR.js/master/aframe/build/aframe-ar-nft.js"></script>
</head>
<body style="margin: 0; overflow: hidden;">
<a-scene
vr-mode-ui="enabled: false"
embedded
arjs="sourceType: webcam; debugUIEnabled: false;"
>
<a-box
material="color: red"
gps-entity-place="latitude: <add-your-latitude>; longitude: <add-your-longitude>;"
scale="30 30 30"
></a-box>
<a-camera gps-camera="gpsMinDistance:10;" rotation-reader> </a-camera>
</a-scene>
</body>
</html>
gps-camera
にgpsMinDistance
プロパティを使用するとGPS更新イベントの発生をメートル単位で制御できます。上記のコードではGPSの変化が10m以下の場合は更新イベントを発生させません。
指定した値以下の位置情報の変化を無視することができるので、頻繁な位置情報の変化によるARコンテンツの「ジャンプ」を防ぐことができます。デフォルトは5mに設定されており個人的には妥当な値だと思いますが、コンテンツのブレが気になる場合はこの値を調整すると良いでしょう。
ARコンテンツまでの距離を表示する
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Location-based AR.js demo</title>
<script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script>
<script src="https://unpkg.com/aframe-look-at-component@0.8.0/dist/aframe-look-at-component.min.js"></script>
<script src="https://raw.githack.com/AR-js-org/AR.js/master/aframe/build/aframe-ar-nft.js"></script>
<style>
#debug {
position: fixed;
z-index: 10000;
background-color: #fff;
padding: 10px;
top: 0;
left: 0;
display: block;
}
</style>
</head>
<body style="margin: 0; overflow: hidden;">
<div id="debug"></div>
<a-scene
vr-mode-ui="enabled: false"
embedded
arjs="sourceType: webcam; debugUIEnabled: false;"
>
<a-box
material="color: red"
gps-entity-place="latitude: <add-your-latitude>; longitude: <add-your-longitude>;"
scale="15 15 15"
></a-box>
<a-text
id="text"
value=""
look-at="[gps-camera]"
scale="30 30 30"
position="0 55 0"
gps-entity-place="latitude: <add-your-latitude>; longitude: <add-your-longitude>;"
></a-text>
<a-camera gps-camera rotation-reader> </a-camera>
</a-scene>
<script>
window.addEventListener('load', () => {
const text = document.getElementById('text');
text.addEventListener('gps-entity-place-update-positon', (event) => {
document.getElementById('debug').textContent = `あと${event.detail.distance}m`;
text.setAttribute('value', text.getAttribute('distanceMsg') + ' left');
});
});
</script>
</body>
</html>
gps-entity-place-update-positon
イベントを使用すると、カメラからARコンテンツまでの距離を取得できます。
イベント名 | 呼ばれるタイミング | Payload |
gps-entity-place-update-positon | gps-entity-placeの指定されているARコンテンツの位置が更新されたとき | { detail: { distance: <Number> }} |
distance
、 distanceMsg
カスタム属性にも値が渡されます。 distance
にはARコンテンツまでの距離、 distanceMsg
には<整数の距離> meter
が入ります。
そのため、下記の方法でも距離を取得できます。
const distanceMsg = document.querySelector('[gps-entity-place]').getAttribute('distanceMsg');
console.log(distanceMsg); // "890 meters"
上記コードでは、画面上部と、a-text
にARコンテンツまでの距離を表示させてます。a-text
にはa-box
と被って文字が見えなくならないように、 position
プロパティで高さを指定しています。公式ドキュメントでは
position
の単位はm
と記載されてるのですが、検証してみたところあまり高さは正確に反映されなそうです。
なお、a-text
などのARコンテンツに距離を表示させる場合は、距離が遠すぎるとサイズが縮小されて文字が読めなくなるので使われるシーンに応じてscaleの調整が必要です。
その他のイベント
gps-entity-place-update-positon
イベントの他、現在の位置を取得する gps-camera-update-positon
イベントなども用意されてます。location basedで使えるカスタムイベントは下記ページ「Custom Events」の「Feature」に「Location Based」と書いてあるものを参照してください。
UI and Events AR.js Documentation
距離に応じてARコンテンツを変化させる
A-FrameのARコンテンツはJavaScriptで動的にプロパティを変化させることができます。この特性と前述で取得できる距離を使って、特定の距離より近づいた場合にARコンテンツの色を変えたり動きをつけたりなど変化をつけると、インタラクティブな体験ができます。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Location-based AR.js demo</title>
<script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script>
<script src="https://unpkg.com/aframe-look-at-component@0.8.0/dist/aframe-look-at-component.min.js"></script>
<script src="https://raw.githack.com/AR-js-org/AR.js/master/aframe/build/aframe-ar-nft.js"></script>
</head>
<body style="margin: 0; overflow: hidden;">
<a-scene
vr-mode-ui="enabled: false"
embedded
arjs="sourceType: webcam; debugUIEnabled: false;"
>
<a-box
material="color: red"
gps-entity-place="latitude: <add-your-latitude>; longitude: <add-your-longitude>;"
scale="30 30 30"
></a-box>
<a-camera gps-camera rotation-reader> </a-camera>
</a-scene>
<script>
window.addEventListener('load', () => {
const el = document.querySelector('[gps-entity-place]');
el.addEventListener('gps-entity-place-update-positon', (event) => {
if(event.detail.distance < 100) {
el.setAttribute('material','color: yellow');
} else {
el.setAttribute('material','color: red');
}
});
});
</script>
</body>
</html>
event.detail.distanc
でARコンテンツまでの距離が取得できるので、条件分岐を使い100以下ではARコンテンツの色を yellow
に、それ以外では red
にします。
組み合わせてみる
これらの手法は組み合わせて使用することが可能です。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Location-based AR.js demo</title>
<script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script>
<script src="https://unpkg.com/aframe-look-at-component@0.8.0/dist/aframe-look-at-component.min.js"></script>
<script src="https://raw.githack.com/AR-js-org/AR.js/master/aframe/build/aframe-ar-nft.js"></script>
<!-- animation-mixtureを使うため -->
<script src="https://cdn.rawgit.com/donmccurdy/aframe-extras/v4.2.0/dist/aframe-extras.min.js"></script>
<style>
body {
font-family: sans-serif;
}
* {
box-sizing: border-box;
}
#distance {
position: fixed;
z-index: 10000;
background-color: rgba(0,0,0,.8);
color: #fff;
text-align: center;
padding: 10px;
top: 10px;
left: 5%;
width: 90%;
display: block;
}
body {
margin: 0;
}
#message {
position: fixed;
z-index: 10;
left: 5%;
bottom: 30px;
width: 90%;
padding: 5%;
color: #fff;
font-weight: bold;
background-color: rgba(0,0,0,.8);
border-radius: 20px;
border: 3px solid #fff;
display: none;
}
</style>
</head>
<body style="margin: 0; overflow: hidden;">
<div id="distance"></div>
<div id="message">
大鎧ドラゴンがあらわれた!
</div>
<a-scene
vr-mode-ui="enabled: false"
embedded
arjs="sourceType: webcam; debugUIEnabled: false;"
>
<!-- 3Dモデル(gltfファイル) -->
<a-assets>
<a-asset-items id="dragon" src="dragon.gltf" ></a-asset-items>
</a-assets>
<a-entity
gps-entity-place="latitude: <add-your-latitude>; longitude: <add-your-longitude>;"
gltf-model="#dragon"
scale="7 7 7"
rotation="0 0 0"
pisition="0 -1 0"
animation-mixer
></a-entity>
<a-light
id="directionLight"
type="directional"
color="#FFF"
intensity="0"
position="-1 1 2">
</a-light>
<a-light
id="ambientLight"
type="ambient"
intensity="0"
color="#FFF">
</a-light>
<a-camera gps-camera="minDistance:10; maxDistance:50" rotation-reader> </a-camera>
</a-scene>
<script>
window.addEventListener('load', function () {
const el = document.querySelector('[gps-entity-place]');
const distanceMsg = document.getElementById('distance');
const message = document.getElementById('message');
const directionLight = document.getElementById('directionLight');
const ambientLight = document.getElementById('ambientLight');
el.addEventListener('gps-entity-place-update-positon', (event) => {
distanceMsg.textContent = `あと${event.detail.distance}m`;
if(event.detail.distance <= 30) {
// 30m以下で明るくする、メッセージ表示、距離非表示
directionLight.setAttribute('intensity',1);
ambientLight.setAttribute('intensity',1);
distanceMsg.style.display = 'none';
message.style.display = 'block';
} else if(event.detail.distance <= 50) {
// 50m以下で近づくほど明るくする、メッセージ非表示、距離表示
directionLight.setAttribute('intensity',1 - event.detail.distance / 50);
ambientLight.setAttribute('intensity',1 - event.detail.distance / 50);
distanceMsg.style.display = 'block';
message.style.display = 'none';
} else {
// 50mより離れると、明るさ0、メッセージ非表示、距離表示
directionLight.setAttribute('intensity',0);
ambientLight.setAttribute('intensity',0);
distanceMsg.style.display = 'block';
message.style.display = 'none';
}
});
});
</script>
</body>
</html>
組み合わせて少しリッチな体験となるようにしてみました。このコードの仕様は下記のようになってます。
- ARコンテンツまでの距離を画面内に表示
- ARコンテンツとの距離50m以下でARコンテンツを表示
- 50m以下で近づくほどライトを強くする(明るくなる)
- 20m以下でライトの強さMax、メッセージを表示
Location Based ARが向いてるケース
一通り、Location Based ARを試してみたところ、向いてるケース向かないケースは下記のようになるかと思います。向いている
- 建造物が少ない公園や開けた場所
- 大きなサイズのARコンテンツ
- ある程度の座標の位置ブレを許容できる
- 表示される高さを厳密に求めない
- 宝探しやアート系のAR
向いてない
- 建造物が多い
- 室内などGPSを正確に取得できない場所
- 小さなサイズのARコンテンツ
- 正確な座標に表示させたい
- 表示される高さを厳密に求める
また向いてないケースであってもアイデア次第では面白い体験を生むことはできると思います。
まとめ
AR.jsのLocation Based ARを試してみましたが、ARコンテンツを表示させるだけでなく、距離が取得できたり、設定を細かくカスタマイズできたりと意外とできることが多いと思いました。まだ発展途上の技術と感じる部分も多々ありますが、一方で限られた条件の中でどのように工夫して良い体験を生むのか考えるのも一つの面白さだと思います。 アイデア次第で面白い使い方もできると思いますので是非試してみてください。
WebAR/VRのお仕事に関するご相談
Bageleeの運営会社、palanではWebAR/VRに関するお仕事のご相談を無料で承っております。
zoomなどのオンラインミーティング、お電話、貴社への訪問、いずれも可能です。
ぜひお気軽にご相談ください。
この記事は
参考になりましたか?
1
0
関連記事
簡単に自分で作れるWebAR
「palanAR」はオンラインで簡単に作れるWebAR作成ツールです。WebARとはアプリを使用せずに、Webサイト上でARを体験できる新しい技術です。
palanARへpalanでは一緒に働く仲間を募集しています
正社員や業務委託、アルバイトやインターンなど雇用形態にこだわらず、
ベテランの方から業界未経験の方まで様々なかたのお力をお借りしたいと考えております。
運営メンバー
Eishi Saito 総務
SIerやスタートアップ、フリーランスを経て2016年11月にpalan(旧eishis)を設立。 マーケター・ディレクター・エンジニアなど何でも屋。 COBOLからReactまで色んなことやります。
sasakki デザイナー
アメリカの大学を卒業後、日本、シンガポールでデザイナーとして活動。
やまかわたかし デザイナー
フロントエンドデザイナー。デザインからHTML / CSS、JSの実装を担当しています。最近はReactやReact Nativeをよく触っています。
Sayaka Osanai デザイナー
Sketchだいすきプロダクトデザイナー。シンプルだけどちょっとかわいいデザインが得意。 好きな食べものは生ハムとお寿司とカレーです。
はらた エンジニア
サーバーサイドエンジニア Ruby on Railsを使った開発を行なっています
こぼり ともろう エンジニア
サーバーサイドエンジニア。SIerを経て2019年7月に入社。日々学習しながらRuby on Railsを使った開発を行っています。
ささい エンジニア
フロントエンドエンジニア WebGLとReactが強みと言えるように頑張ってます。
Damien
WebAR/VRの企画・開発をやっています。森に住んでいます。
ゲスト bagelee
かっきー
まりな
suzuki
miyagi
ogawa
雑食デザイナー。UI/UXデザインやコーディング、時々フロントエンドやってます。最近はARも。
いわもと
デザイナーをしています。 好きな食べ物はラーメンです。
taishi kobari
フロントエンドの開発を主に担当してます。Blitz.js好きです。
kubota shogo
サーバーサイドエンジニア。Ruby on Railsを使った開発を行いつつ月500kmほど走っています!
nishi tomoya
aihara
グラフィックデザイナーから、フロントエンドエンジニアになりました。最近はWebAR/VRの開発や、Blender、Unityを触っています。モノづくりとワンコが好きです。
nagao
SIerを経てアプリのエンジニアに。xR業界に興味があり、unityを使って開発をしたりしています。
Kainuma
サーバーサイドエンジニア Ruby on Railsを使った開発を行なっています
sugimoto
asama
ando
iwasawa ayane
oshimo
異業界からやってきたデザイナー。 palanARのUIをメインに担当してます。 これからたくさん吸収していきます!