NoodlでARマーカーを読み込む

[GWアドベントカレンダー](https://gw-advent.9wick.com/calendars/2020/70)３日目🍜
ギリギリの投稿となりましたがなんとか間に合った...！この記事は、[【AR.js入門】簡単にWebARで遊んでみた【A-Frame使うよ】](https://qiita.com/sakaryu/items/769a2a538baf7e4ee1c7)の内容をNoodlで再現したものになります。結構ゴリ押しなやり方で実現したので、今後、検討が必要ですが備忘録として残します。

#つくったもの
Noodlのプレビュー画面でARマーカーを読み込み、3Dオブジェクトを表示するサンプルです。
**[こちら](https://pentake.github.io/aframe-arjs-noodl/20200501_deploy/index.html)**からサンプルページにアクセスできます。
![arMarker_noodl.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526082/e91b1819-f416-b968-2c1f-3707ac86d8b9.gif)
※ アクセスするとカメラの許可を聞かれるので、許可してください。
※ Safari / Chrome での動作確認は取れています。ブラウザの条件を満たしていれば、PCでもスマホでもARマーカーを読み込めると思います。

#ARマーカー
今回使用したARマーカーです。サンプルページでカメラを起動した後、このマーカーをカメラで読み込むとサンタが現れます。
![hiro_marker.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526082/2227ec5d-b0e5-6614-4198-89877dac6757.png)

#NoodlでARに挑戦
**バージョン**
・macOS 10.14.5
・Noodl 2.0.2
・A-Frame 0.8.2
・AR.js 1.5.0

**参考記事**
[Noodl v2.0.2でa-frameを表示させる方法について](https://www.crossroad-tech.com/entry/noodl202-a-frame)
Noodl v2.0.0でのJavaScriptの書き方で参考にさせていただきました。

#キッカケは、初めてのハッカソン🔰
NoodlとARへの挑戦は、4月18日の[オンラインハッカソン](https://protoout.connpass.com/event/172136/)がキッカケでした。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">初ハッカソンがオンライン... 不安とワクワクが入り混じっております... <a href="https://twitter.com/hashtag/ProtoOut?src=hash&amp;ref_src=twsrc%5Etfw">#ProtoOut</a></p>&mdash; ぺんたけ (@penpenchapen) <a href="https://twitter.com/penpenchapen/status/1251141291691225098?ref_src=twsrc%5Etfw">April 17, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

ネタが決まり、[A-Frame](https://aframe.io)と[AR.js](https://ar-js-org.github.io/AR.js-Docs/)を使いNoodlでARマーカーを読み込むことに。

しかし、NoodlとA-Frame、AR.jsの連携に苦戦してしまい時間切れ。
結局、Noodlは使わずにデモを行うことになりました。

発表は無事にできました。
メンバーの方々のおかげです、本当に感謝しています。

ただ、悔しかった...
ということで...

**🔥悔しさをバネに、NoodlでのARマーカー読み込みにリベンジしました！！！🔥**

#上手くいかなかった原因は？
A-Frameの要素（ `a-scene` `a-assets` などの a- から始まるもの... ）をブラウザで読み込むと、`a-scene` の子要素として `<canvas class="a-canvas"...>` が自動で生成されます。これは、Chromeの検証で確認しないと分かりません。

**そして、このクラス名 a-canvas の `canvas` が `body` 要素の直下に置かれていないと、3Dオブジェクトを上手く描写してくれないようでした。**
※ これはあくまで試行錯誤から得た仮説なので、確実な情報を知っている方いらっしゃいましたら教えていただきたいです。

ハッカソンの時は、Noodlのcanvasノードを使って3Dオブジェクトを表示しようとしていました。でも、3Dオブジェクトを描写する要素は、クラス名 a-canvas の `canvas` であったため(?)描写されていなかったようです（推測）

#innerHTMLを使って解決！（ゴリ押し）
下記のJavaScriptノードの記述では、innerHTMLを使い、body要素の直下にA-Frameの要素（ `a-scene` `a-assets` など）を置く操作をしています。これで、クラス名 a-canvas の `canvas` が適切な階層に自動で生成されます。

[innerHTML](https://www.w3schools.com/jsref/prop_html_innerhtml.asp)は、指定した要素の中身を書き換えるプロパティです。Noodlでは、`body` の子要素としてビジュアルノード（正しくは `div` `input` などの要素）が入っています。しかし、`body` のinnerHTMLに何かを代入すると、元のデータが上書きされてしまいます。つまり、Noodlのビジュアルノードが消え、上書きされたデータだけ残ります。

今回の例で説明してみます（下図を参照）
Santa_ARというGroupノード（正しくは `div` 要素）が１つだけありますが、これは `body` のinnerHTMLにA-Frameの要素を代入することで消えます。代わりに、代入されたA-Frameの要素が残ります。
（じゃあGroupノードいらないじゃん！ってなるのですが、ブラウザ表示のrootを設定するために必要みたいです）
![noodl.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/526082/211b19f2-1ec8-7f0c-508d-739746c8bcf3.png)
**解決したは良いのですが、この方法、ゴリ押しなので正直オススメできません。
Noodlのビジュアルノードが消えてしまうので... Noodlで構築したUIとARマーカーで読み込んだ3Dオブジェクトの夢の共演ができないってことです... くぅ... 良い方法はないものか...**

####JavaScriptノードの記述

```
define({
	inputs:{
	    mySignal: 'signal',
	    scriptLoaded: 'boolean'
	},
	mySignal:function(inputs,outputs) {
		if (!inputs.scriptLoaded) {
                return;
        }
        var body = document.getElementsByTagName('body')[0];
        body.innerHTML = 
        '<a-scene embedded arjs="sourceType:webcam; debugUIEnabled:false; trackingMethod:best;" vr-mode-ui="enabled: false">'+
		'<a-assets>'+
        '<a-asset-item id="santa-obj" src="santa.obj"></a-asset-item>'+
        '<a-asset-item id="santa-mtl" src="santa.mtl"></a-asset-item>'+
        '</a-assets>'+
        '<a-marker preset="hiro">'+
        '<a-obj-model id="santa" src="#santa-obj" mtl="#santa-mtl" position="0 0 0" scale="0.5 0.5 0.5" rotation="0 0 0"></a-obj-model>'+
        '<a-text value="Santa!!!" position="0 1.3 0" align="center"></a-text>'+
        '</a-marker>'+
        '<a-entity camera></a-entity>'+
        '</a-scene>';
        // console.log(body);
	}
})
```

#Noodlプロジェクトデータ
Githubで公開しています。
**[こちら](https://github.com/pentake/aframe-arjs-noodl)**からダウンロードして、noodl_projectというフォルダをNoodlで読み込むと使えます！
完成している状態なので、プレビュー画面を見ながらARマーカーを読み込ませるとサンタさんが現れます。

※ ちなみに、Noodlにはブラウザでプレビューする機能(正確にはローカルにアクセス)があるのですが、それだと上手くいきません。ブラウザの制約(?)で、httpsじゃないとカメラが上手く作動しないようです。サーバーにデプロイすれば上手く動きます。

#おわりに
リベンジは果たせたのですが、歯切れが悪かったです。でも、ARマーカーがNoodlで読み込めた時の達成感が半端じゃなかったですね。

これから、ARマーカーで読み込んだ3DオブジェクトとNoodlのビジュアルノードとの夢の共演を果たす方法を探す旅に出ます... 探さないでください...