ブラウザで マーカーベース AR #haiku

この記事は RECRUIT MARKETING PARTNERS Advent Calendar 2018 の投稿記事です。

こんにちは、キッズリー開発グループの @tondol です。好きなハッシュタグは #ようちか安心委員会 です。

突然ですが、 皆さん AR やっていますか? iOS なら ARKit 、 Google にはARCore プロジェクトがあったりと、スマートフォンで動かす AR フレームワークが続々登場していますね。

最新の AR フレームワークでは、上記の動画のようにかなり高度なインタラクションまで実現出来たりしますが、今回はもう少しハードルを下げて 昔ながらのマーカーベース AR を取り上げます

マーカーベース (マーカー型) AR とは: 黒枠で囲まれた正方形パターン (マーカー) をカメラで認識し、マーカーを基準に 3D コンテンツを重畳するタイプの AR を指します。 ARToolKit でよく使われる Hiro マーカー に見覚えのある方は結構いらっしゃるのではないでしょうか?

今回紹介する方法で作った AR コンテンツのデモは、なんとブラウザ単体で動作します。専用アプリのインストールが不要なため、ネイティブアプリで動作する AR コンテンツとはまた違った場面で役立つことがあるかもしれません。

というわけで、この記事では スマホで手軽に AR を試すことのできるライブラリと、それらを使ったデモの実装方法 を紹介します。

今回作成したデモ

マーカーをカメラで捉えると マーカー上に立方体が表示されるデモ を作成しました1)表示されるライオンのようなキャラクターは弊社の内製開発組織発の ゆるキャラ・リファライオン です。。単に立方体を表示するだけではツマラナイので、立方体の全面にアニメーションするテクスチャを貼り付けています2)実際は立方体にテクスチャを貼り付けているのではなく、少し手前にテクスチャ付きの板ポリゴンを置いています。

カメラ付スマートフォンや PC でご覧の方は、こちらの デモページ からもお試しいただけます。マーカー画像は rmp-marker.png からダウンロードしてください。

カメラの使用権限を求められた場合は、許可しないとデモが動作しません。ご注意ください。

利用するライブラリ

今回のデモで利用している JavaScript ライブラリを紹介します。

ライブラリ 概要
a-frame
(Ver. 0.7.1)
WebVR を実現するフレームワーク。 HTML 内にカスタム要素を記述するだけで VR コンテンツを実現できる抽象度の高いライブラリです。
AR.js
(Ver. 1.6.2)
a-frame と組み合わせることで、ブラウザ上で手軽に AR を実現することのできるライブラリです。
html2canvas
(Ver. 0.4.1)
HTML 要素をレンダリングした結果を画像化するライブラリです。
a-frame-html-shader
(Ver. 0.2.0)
HTML 要素をレンダリングした結果を a-frame のテクスチャとして扱うためのライブラリ。 html2canvas に依存しています。

動作環境

今回のデモは、下記の環境で動作することを確認しています。

  • iOS 11.0 以上 / Safari (iOS 版の Chrome は不可)
  • Android 5.0 以上 / Chrome (WebGL, WebRTC 対応のバージョンが必須)
  • macOS High Sierra / Chrome (同上)

古いバージョンの OS や、ここに挙げた以外の環境では動作しないことがあります ので、予めご了承ください。

index.html (HTML)

今回紹介するデモのソースコードは tondol/rmp-advent-calendar-2018 のリポジトリにあります。重要な部分を抜粋して説明していきます。

<!-- テクスチャの中身を描画する要素。 -->
<div id="target">
    <div class="item-image"><img src="./referlion.jpg" /></div>
    <div class="item-marquee">ブラウザでARが動くんだお〜</div>
</div>

何の変哲もない HTML の断片ですが、ここで記述した #target のレンダリング結果が後述のテクスチャとして使われることになります。HTML 単体では特にアニメーションしないので、 .item-marquee の要素を後から JavaScript でアニメーションさせます。

次に進みましょう。

<!-- AR コンテンツの定義。 -->
<a-scene embedded arjs="debugUIEnabled:false" vr-mode-ui="enabled:false">
    <a-marker preset="custom" type="pattern" url="pattern-marker.patt">
        <a-box position="0 0.6 0"></a-box>
        <a-plane position="0 0.6 0.51" material="shader:html;target:#target;fps:24;width:640;height:640"></a-plane>
    </a-marker>
    <a-entity camera></a-entity>
</a-scene>

この見慣れない a- から始まる要素群が、 a-frame および AR.js によって提供される、今回のデモのキモになる部分 です。いくつか要素がありますので、簡単にご紹介します。

要素 概要
a-scene 3D シーン全体を表現する要素。今回は VR 機能は不要なので、VR 関連の UI を無効化しています。
a-marker AR マーカーを表現する要素です。マーカーを基準に配置される 3D オブジェクトは、この要素の子要素として記述していきます。
カスタムマーカーとして pattern-marker.patt が指定されていますが、このデータは後述のマーカージェネレーターで作成できます。
a-box 立方体を表現する要素です。position 属性でマーカーを基準とした座標系 (原点がマーカーの中心で、Y 軸がマーカーを水平に置いたときの鉛直方向) における位置を設定します。
a-plane 板ポリゴンを表現する要素。 position 属性については a-box と同様です。
materials 属性で html-shader を使ったテクスチャの設定を行っています。
具体的には、 #target のレンダリング結果 (640 x 640 px) を 24 fps でテクスチャに反映する設定にしています。
a-entity カメラプレビューを表現する要素です。
AR.js のチュートリアルの通りに a-scene の直下に置いています。

主要な記述はコレだけですが、 a-frame と AR.js の力でバッチリ AR が動作します 。便利な世の中になりましたね!! しゅごい・・・

index.js (JavaScript)

続いて index.html の中でロードされている index.js の方も見ていきましょう。

AR の主要部分は HTML 側の定義だけで動作するため、こちらはテクスチャ反映元の DOM をアニメーションさせるだけの内容になっています。

// レンダリング開始後に ready 関数を実行。
document.addEventListener('DOMContentLoaded', () => {
    const scene = document.querySelector('a-scene');
    if (scene.hasLoaded) {
        ready();
    } else {
        scene.addEventListener('renderstart', ready);
    }
});

scene のレンダリングがスタートしたら、 ready 関数を実行するようにしています。

function ready() {
    ...
    const marquee = document.querySelector('#target .item-marquee');
    // フォントサイズの調整。
    css(marquee, {
        'font-size': `${640 / marquee.textContent.length}px`,
    });

ready 関数の中では、ちょうどテキストがテクスチャの横幅いっぱいになるように、 .item-marquee 内のフォントサイズを動的に調整しています。

let t = 0;
// render 関数を毎フレーム実行する。
function render() {
    if (t >= 1.0) {
        t -= Math.floor(t);
    }
    // 要素の左マージンを変化させる (右から左に流れるアニメーションを実現) 。
    const value = 640 * (1.0 - t * 2.0);
    css(marquee, {
        'margin-left': `${value}px`,
    });
    t += 0.005;
    requestAnimationFrame(render);
}
render();

若干込み入ったコードですが、 render 内の処理が毎フレーム実行されるようになっています。テキストが右から左に流れていくアニメーションを実現するため、 フレームごとに適切な margin-left の値を計算し、動的に CSS に反映 しています。

ちなみに AR 機能に関係する部分をすべて削って #target 単体のレンダリング結果を確認すると、下記の画像のようになります。

index.js 自体は何の変哲もないスクリプトですが、 html-shader のおかげでアニメーションの内容がテクスチャに反映され、動的な AR コンテンツを実現できるというわけです。

マーカーの作り方

AR.js の開発者により ジェネレーター が用意されており、カスタムマーカーのパターンデータも簡単に作成できます。

四角い枠を除いた文字・画像を含むパターンを PNG で作成・アップロードし、 DOWNLOAD MARKER のボタンを押すと、そのまま AR.js で使える pattern-marker.patt ファイルがダウンロードできます

マーカーの黒枠の割合はカスタマイズできますが、デフォルトの 0.5 にしておくと比較的認識が安定するようです。

おわりに

この記事では、 AR.js と html-shader の組み合わせによる Web AR のデモを紹介しました。

以前、プライベートで AR スタンド花 の制作に参加した際3)AR スタンド花のプロジェクトでは、自分を含む数人のグループで AR コンテンツを作成しました。特にエンジニアの@hogesako さんや 3D モデラーの @am_coffee_ さん (どちらの方もプライベートの友人で、弊社とは関係ありません) には色々お世話になりました。、今回紹介したライブラリで web ページを実装したのですが、少ない記述量で手軽に AR コンテンツを実現することができました。

また、アプリのインストールなしで AR コンテンツが楽しめる という利点がうまく働き、多くの人にスマホで AR スタンド花を試していただくことができました。 AR コンテンツを作りたいが、独自アプリのインストールを求めるのはハードルが高い……と言ったケースなどで AR.js が有力な選択肢になってくるのではないでしょうか。

リクルートマーケティングパートナーズでは、プライベートの趣味でもエンジニアリング力をついつい発揮してしまう「やっていき」力を持つエンジニア募集しております

脚注

脚注
1 表示されるライオンのようなキャラクターは弊社の内製開発組織発の ゆるキャラ・リファライオン です。
2 実際は立方体にテクスチャを貼り付けているのではなく、少し手前にテクスチャ付きの板ポリゴンを置いています。
3 AR スタンド花のプロジェクトでは、自分を含む数人のグループで AR コンテンツを作成しました。特にエンジニアの@hogesako さんや 3D モデラーの @am_coffee_ さん (どちらの方もプライベートの友人で、弊社とは関係ありません) には色々お世話になりました。