【WebAR】AR.js＋A-Frameで遊ぶ


## はじめに
「オリジナルの3Dモデルが**ARで簡単に表示**できたら何かに使えそう！」
ということで、簡単に実装できる方法はないか探して実践してみました。

## WebAR とは？
**「Webブラウザ上でARが体験できる仕組み」** です。

以下のメリットがあります。とにかく**手軽さ・簡単さ**が大きな特徴！
- アプリのインストールが必要ない
- URLをシェアするだけで簡単に共有できる
- ライブラリや作成ツールが充実していて手軽に作成できる

## 実装に使用したもの

以下のフレームワークとライブラリを使うことで簡単に作成できます。

- A-Frame
    - https://aframe.io/
    - Web 上で 3D コンテンツや VR 体験を簡単に作成できるフレームワーク
    - マークアップ言語（HTMLなど）を使って 3D オブジェクトやシーンを作成できる
- AR.js
    - https://ar-js-org.github.io/AR.js-Docs/
    - Web 上で AR 体験を実現するためのライブラリ
    - A-Frame と組み合わせることで、Web ブラウザを通じて簡単に AR コンテンツを作成できる

それぞれの役目としては、
「**A-Frameで、HTMLタグによるシーン構築・3Dモデル・カメラの動き等を容易にコントロール**し、**AR.jsで、ARに特化した体験（例えばマーカーなど）を軽量かつハイパフォーマンスに構築**してくれる」
といったところでしょうか。

## フォルダ構成
まず、フォルダ構成は以下です。
```
.
└── src/
    ├── hiro.patt
    ├── index.html
    └── Strawberry.gltf
```
- hiro.patt は、AR.js のデフォルトマーカーです。
    - AR.js には既にいくつかマーカーが用意されており、とりあえず動くことを見たいので、今回は以下のHiroマーカーを使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3872071/acbea3c1-88da-3f4d-be54-98cd8e1a3dfb.png)

- Strawberry.gltf は、「Free3D」というサイトから取得しました。
    - 参考：https://free3d.com/ja/3d-models/
    - ちなみに、glTF (GL Transmission Format) とはJSONによって3Dモデルやシーンを表現する一般的なフォーマットです。


## 実装
index.html の実装は以下です。
```html
<!DOCTYPE html>
<html>
  <head>
    <title>AR Example2</title>
    <!-- A-Frameを読み込む -->
    <script src="https://aframe.io/releases/1.6.0/aframe.min.js"></script>
    <!-- AR.js(A-Frame用)を読み込む -->
    <script src="https://raw.githack.com/AR-js-org/AR.js/master/aframe/build/aframe-ar.js"></script>
    <meta name="apple-mobile-web-app-capable" content="yes" />
  </head>
  <body style="margin: 0; overflow: hidden">
    <!-- シーンを作成 -->
    <a-scene embedded arjs="sourceType: webcam;">
      <a-assets>
        <!-- 3Dモデルを読み込む -->
        <a-asset-items id="Strawberry" src="/Strawberry.gltf"></a-asset-items>
      </a-assets>
      <!-- マーカー（今回はhiroマーカー）を検出して立方体を表示する -->
      <!-- emitevents=true でマーカーの検出イベントを有効にする -->
      <a-marker preset="hiro" emitevents="true">
        <!-- 3Dモデルを呼び出す -->
        <!-- gltfファイル（a-gltf-modelタグ）-->
        <!-- <a-gltf-model scr="#Strawberry"></a-gltf-model> ←なぜか表示されない場合がある -->
        <a-entity
          position="0 0 0"
          rotation="0 0 0"
          scale="0.7 0.7 0.7"
          gltf-model="#Strawberry"
        >
      </a-marker>
      <a-entity camera></a-entity>
    </a-scene>
    <script>
      document
        .querySelector("a-marker")
        .addEventListener("markerFound", (event) => {
          console.log("Marker Found", event);
        });

      document
        .querySelector("a-marker")
        .addEventListener("markerLost", (event) => {
          console.log("Marker Lost", event);
        });
    </script>
  </body>
</html>

```
先人たちの作ってみたサイトを見ても王道な形かなと思います。

以下、躓いたところです。
- A-Frameの`<a-gltf-model />`というタグを使おうとしましたが、**なぜか3Dオブジェクトが表示されない**ことがあったので、`<a-entity />`を使い、`gltf-model`という属性にIdを指定する形にしました。
- このindex.htmlファイルをそのままブラウザで開くと以下のエラーが出ます。
    ```
    Access to fetch at 'file:///{自分が配置したパス}/Strawberry.gltf' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: chrome, chrome-extension, chrome-untrusted, data, http, https, isolated-app.
    ```
    このエラーメッセージは、CORS（Cross-Origin Resource Sharing）ポリシーに関連しています。具体的には、**ブラウザがローカルファイル（file:///）からリソースを読み込むことを許可していない**ために発生しています。
    CORSは、異なるオリジン(プロトコル+ドメイン+ポート)間でのリソースの共有を制御するためのセキュリティ機能です。**ローカルファイルを直接ブラウザで開くと、オリジンがnullと見なされ**、他のオリジンからのリソースへのアクセスがブロックされます。

    どこかのサーバーに配置すればいいのですが、今回はローカルで簡易的なサーバーを立てて、そのサーバーを通してファイルにアクセスすることにします。
    自分のPCには`Node.js`が入っていたので、VSCodeのターミナルから以下を実行しました。
    ```
    npx http-server
    ```
    その後、ブラウザで http://localhost:8000/ にアクセスすることで解消されました！

## 終わりに
上記を通して以下のように表示することができました。
（右側に開発者ツールのコンソールを表示しています）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3872071/c406898c-162c-1960-6aa7-1ae1f2f95f0a.png)

ちなみに、`<script/>`タグに書いていたイベントのおかげで、マーカーを検知できたかどうかを確認することができ、これが地味にありがたかったです！
動作確認の際、3Dオブジェクトが表示されないとき、「マーカーが検知できていないのか」「3Dオブジェクトが表示できていないのか」の区別をつけるためですね。
これから実装してみようという方はぜひこれも書いておきましょう。

WebARを使って、3Dオブジェクトだけでなく、画像や動画なども表示できるので使い方はたくさんありそうです。