はじめに
ARアプリの作り方はいろいろありますが、ブラウザベースのWebARであれば専用アプリをインストールすることなくARを楽しめます。
つまり、ユーザにとってARまでのアクセスが早いです。合わせてQRコードを使うことで、ユーザが実際にARするまでを素早く実現するアプリをデモ的に作ってみました。
今回はホスティングにFirebase、フレームワークにAR.js+A-Frame、モデリングにWindows10標準付属の3D Builderを使って、簡単ながら自作モデルを自ホストで提供する構成を無料で作りました。
Firebaseとは
GoogleのMBaaSで、モバイルアプリのバックエンドクラウドサービスです。
大変高機能なのですが、今回使うのはそのうちの単なるHostingサービスです。
使い方はとても簡単です。(参考記事:FirebaseでWebサイトを無料でサクッと公開してみる)
Hostingの無料枠は、総アップロード容量と、総ダウンロード容量、で決まっています。
アップロード容量は、過去にアップロードしたバージョンの分も累積されるので、不要なバージョンは適宜消しておくとよいでしょう。
A-Frameとは
WebGLなどの技術を使い、ブラウザ上で3Dモデルを表示する仕組みを、主にHTMLタグだけで実現するフレームワークです。開発元はMozillaです。
AR.jsとは
ブラウザベースでARを実現できるライブラリです。A-Frameと組み合わせることでHTMLタグの記述だけで簡単なARアプリを作れます。
AR.jsではARToolkitが使われています。黒枠を認識してカメラとの相対位置・姿勢を計算し、CGを表示します。
オリジナルデザインマーカも作れます。
マーカの中に入れる画像を準備して、専用ページにアップロードすることで、認識に使うファイル(pattern-marker.patt)と画像ファイル(marker.png)がダウンロードできます。
また、黒枠内のパターンをマッチングすることで、複数のマーカを区別できます。
具体的には後述のHTML解説にて。
サンプルアプリ
マーカの準備
オリジナルデザインのマーカとして適当に次の2つを作ります。
オブジェクト作成
3D Builderで次の2つのオブジェクトを作り、OBJ形式で保存します。
それぞれ、「grass.obj, grass.mtl」、「signpanel.obj, signpanel.mtl, oak.jpg」というファイル一式で構成されます。
適当なフォルダに置き、後ほどHTMLで読み込みます。
形に特に意味はありません、この辺はお好みで・・・
HTMLの準備
A-Frame+AR.jsを使ったコードは、AR.jsのサンプルにあるminimal.htmlだとたった8行です。
プリインのマーカに半透明の立方体を表示するコンテンツです。
<!-- Augmented Reality on the Web in 10 lines of html! https://github.com/jeromeetienne/ar.js -->
<script src="https://aframe.io/releases/0.8.0/aframe.min.js"></script>
<script src="../build/aframe-ar.min.js"></script>
<body style='margin : 0px; overflow: hidden;'>
<a-scene embedded arjs='sourceType: webcam;'>
<a-box position='0 0.5 0' material='opacity: 0.5;'></a-box>
<a-marker-camera preset='hiro'></a-marker-camera>
</a-scene>
</body>
今回は、
- 看板のオブジェクトに文字を表示
- 文字の内容はマーカによって変化
- 草がくるくる回るアニメーション付き
っていうコンテンツにするのでちょっとだけ長くなりますが、内容は難しくないです。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<!-- A-Frame ライブラリの読み込み -->
<script src="https://aframe.io/releases/0.8.0/aframe.min.js"></script>
<!-- AR.js ライブラリの読み込み -->
<script src="https://jeromeetienne.github.io/AR.js/aframe/build/aframe-ar.js"></script>
<title>WebAR Demo</title>
</head>
<body style='margin : 0px; overflow: hidden; font-family: Monospace;'>
<!-- 3Dオブジェクトの読み込み -->
<!-- OBJファイルはモデル形状、MTLファイルはテクスチャ情報 -->
<!-- ここで指定したIDを呼び出し時に使う -->
<a-assets>
<a-asset-item id="signpanel_mtl" src="static/models/signpanel/signpanel.mtl"></a-asset-item>
<a-asset-item id="signpanel_obj" src="static/models/signpanel/signpanel.obj"></a-asset-item>
</a-assets>
<a-assets>
<a-asset-item id="grass_obj" src="static/models/grass/grass.obj"></a-asset-item>
<a-asset-item id="grass_mtl" src="static/models/grass/grass.mtl"></a-asset-item>
</a-assets>
<!-- ARオブジェクトを描画するシーンの定義 -->
<a-scene stats embedded arjs='debugUIEnabled: false; sourceType: webcam; detectionMode: mono; maxDetectionRate: 30; canvasWidth: 240; canvasHeight: 180'>
<!-- ARマーカに対する描画オブジェクト -->
<a-marker preset="custom" type="pattern" url="static/marker/pattern.patt">
<!-- オブジェクト1つめの配置 -->
<a-obj-model src="#signpanel_obj" mtl="#signpanel_mtl" position="0 0 0" rotation="-100 0 0" scale="0.05 0.05 0.05" visible="true"></a-obj-model>
<!-- a-entityタグでオブジェクトやアニメーションの定義をまとめる -->
<a-entity>
<a-obj-model src="#grass_obj" mtl="#grass_mtl" position="-0.3 0 0" rotation="-90 0 0" scale="0.03 0.03 0.03" visible="true"></a-obj-model>
<!-- アニメーションもHTMLタグで定義可能 -->
<a-animation attribute="rotation" dur="5000" fill="forwards" to="0 360 0" repeat="indefinite"></a-animation>
</a-entity>
<!-- テキストも描画可能 -->
<a-text value="Augmented" position='-0.8 1.9 -0.1' rotation="0 0 0" scale="1.5 1.5 1.5" color="#111111"></a-text>
<a-text value="Reality" position='-0.3 1.3 -0.1' rotation="0 0 0" scale="1.5 1.5 1.5" color="#111111"></a-text>
</a-marker>
<!-- マルチマーカの場合はa-markerタグを複数書く -->
<a-marker preset="custom" type="pattern" url="static/marker/pattern2.patt">
<a-obj-model src="#signpanel_obj" mtl="#signpanel_mtl" position="0 0 0" rotation="-100 0 0" scale="0.05 0.05 0.05" visible="true"></a-obj-model>
<a-entity>
<a-obj-model src="#grass_obj" mtl="#grass_mtl" position="-0.3 0 0" rotation="-90 0 0" scale="0.03 0.03 0.03" visible="true"></a-obj-model>
<a-animation attribute="rotation" dur="5000" fill="forwards" to="0 360 0" repeat="indefinite"></a-animation>
</a-entity>
<a-text value="Multi Marker" position='-0.7 1.7 -0.1' rotation="0 0 0" scale="1.2 1.2 1.2" color="#111111"></a-text>
</a-marker>
<!-- カメラオブジェクトの配置 -->
<a-camera-static/>
</a-scene>
</body>
</html>
これをFirebaseのHosting機能にデプロイし、URL接続するだけです!
ね、簡単でしょ?
補足
対応OS・ブラウザ
モバイル端末での動作としては、AR.jsの制約で下記環境が必要です。
- Android5.1以上のChrome
- iOS11以上のSafari
また、モバイル端末のブラウザからだとマーカ認識の処理あたりで止まってしまうことがありました。(原因不明)
カメラの許可とHTTPS接続
HTMLアクセスはHTTPSでないといけません。カメラを使うので、ブラウザがHTTPSでないとAPI有効にしてくれません。ローカルで試せるかどうかもブラウザによりけりです。(Edge, Chromeはローカルでカメラ許可できたと思う)
ちなみにFirebaseのHostingはデフォルトでHTTPS接続を提供してくれます。すごい。
3Dオブジェクト準備について
A-Frameが対応している形式であれば、どうやって作ってもどこからか持ってきてもOKです。UnityのAssetStoreなどで事足りるのであればそれが一番簡単でしょう。
今回はあくまで自前で作る、でもなるべく簡単に、というコンセプトで、3D Builderを使っています。立方体や円柱などのプリミティブの組み合わせで、単色・木目・大理石程度のテクスチャであれば、十分作れます。
QRコード作成について
QRコード作成はフリーのサイトが数多くありますので、Google先生に聞けばすぐ見つかるでしょう。
QRコードを作成したら、マーカを印刷する紙に、ARマーカと合わせてQRコードも印刷してしまえば、完了です!
なおARマーカ内部の空白部分のQRコードを印刷しても認識はできますので、マーカ単体で完結させるならこればよいでしょう。
https://jeromeetienne.github.io/AR.js/three.js/examples/arcode.html
https://medium.com/arjs/ar-code-a-fast-path-to-augmented-reality-60e51be3cbdf
ただし、マルチマーカで使う場合、マーカを区別する処理の精度が落ちるかもしれませんので注意です。(未検証)
各種注意点
AR.js
マルチマーカで結構ハマりました。
- 全く認識してくれないとき
マーカ内の画像の線が細すぎると認識されない可能性が高いようです。文字なら太い文字に、絵柄ならはっきりした形状のもの(アイコンなど)が向いているようです。 - 誤認識が多いとき
マーカ内の画像の余白が似たような位置にあると誤認識につながりやすいようです。
あとマーカの特性上、点対称な画像を使うと向きを正確に計算できず、誤認識につながります。
有効な対処としては、アイコンのような画像をマーカ四隅のどこかに寄せるように配置するとよいようです。
A-Frame
a-obj-modelタグのrotation属性のZ座標回転にバグがある気がしている… Z軸に値を入れるとY軸が回転する。Y軸に値をいれてもY軸が回転する。何か解釈を間違っているのかもしれないがよくわからなかった…
おわりに
今回紹介したのはマーカー上に3Dオブジェクトを出すレベルですが、ARcoreやARkitだとマーカーもいらないですよね。(A-FrameでもARcore連携できるみたいです。参考記事)
実際、ARって言葉の幅がとても広くて、極端な話、現実の物体に追従する何かが画面上に出てればもうAR、みたいなところもあったりします。
でも、低レベルと思われるコンテンツでも、それが簡単に実現できるのであれば、新しい体験を提供できる人が増えて、それだけでも結構世界が変わっていくと思うんですよね。だから簡単にできる、って大事だと思います。
(10年前は今回のサンプルを作るだけでもC++でたくさんのコードをかかなきゃいけなかった…しかもWebアプリじゃないのに。)
アイデアがある方はどんどん形にしていってほしいなと思います!