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


GWアドベントカレンダー3日目🍜
ギリギリの投稿となりましたがなんとか間に合った...!この記事は、【AR.js入門】簡単にWebARで遊んでみた【A-Frame使うよ】の内容をNoodlで再現したものになります。結構ゴリ押しなやり方で実現したので、今後、検討が必要ですが備忘録として残します。

つくったもの

Noodlのプレビュー画面でARマーカーを読み込み、3Dオブジェクトを表示するサンプルです。
こちらからサンプルページにアクセスできます。

※ アクセスするとカメラの許可を聞かれるので、許可してください。
※ Safari / Chrome での動作確認は取れています。ブラウザの条件を満たしていれば、PCでもスマホでもARマーカーを読み込めると思います。

ARマーカー

今回使用したARマーカーです。サンプルページでカメラを起動した後、このマーカーをカメラで読み込むとサンタが現れます。

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を表示させる方法について
Noodl v2.0.0でのJavaScriptの書き方で参考にさせていただきました。

キッカケは、初めてのハッカソン🔰

NoodlとARへの挑戦は、4月18日のオンラインハッカソンがキッカケでした。

ネタが決まり、A-FrameAR.jsを使い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 の canvasbody 要素の直下に置かれていないと、3Dオブジェクトを上手く描写してくれないようでした。
※ これはあくまで試行錯誤から得た仮説なので、確実な情報を知っている方いらっしゃいましたら教えていただきたいです。

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

innerHTMLを使って解決!(ゴリ押し)

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

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

今回の例で説明してみます(下図を参照)
Santa_ARというGroupノード(正しくは div 要素)が1つだけありますが、これは body のinnerHTMLにA-Frameの要素を代入することで消えます。代わりに、代入されたA-Frameの要素が残ります。
(じゃあGroupノードいらないじゃん!ってなるのですが、ブラウザ表示のrootを設定するために必要みたいです)

解決したは良いのですが、この方法、ゴリ押しなので正直オススメできません。
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で公開しています。
こちらからダウンロードして、noodl_projectというフォルダをNoodlで読み込むと使えます!
完成している状態なので、プレビュー画面を見ながらARマーカーを読み込ませるとサンタさんが現れます。

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

おわりに

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

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