ペルソナ玲音を召喚するARを、A-Frameを使って実装しました。今回はマーカーに依存しないマーカーレスなARで、任意の座標にペルソナ玲音の3Dモデルが「浮いている」ARを実装してみることにします。
なお、「ペルソナ玲音」とはなんぞや?という方がいらっしゃるかと思いますが、ざっくりウィキペディアあたりをご参照ください。玲音を好きになりましょう。
前述しましたが、今回はマーカーレスなARとして実装します。
マーカーベースなARは「3Dモデルを召喚する」手法としては王道ですが、ユーザーにURLを渡しただけでは動作しません。何らかの方法で、ユーザーにマーカーを準備させなければならないのが難点です。名刺とかにマーカーを印刷してURLと一緒に渡すなど、物理(フィジカル)なものを利用すれば手段がないわけではありません。とはいえ、ネット上でのみやり取りする際にはこの方法が使えないため、やっぱりマーカーを準備する分の手間はどうしても増えます。
その点、マーカーレスなARはユーザーにURLさえ渡せばすぐ動作するのが最大のメリット。SNSなどにURLだけ掲載しておけば、あとはユーザーにブラウザ経由でアクセスさせるだけです。場合によっては、SNSアプリの内部ブラウザでは動作しないケースがありますが、そこはChromeやSafariでアクセスするよう誘導すればなんとかなるでしょう。
JSによるwebARの実装である以上、現状では3DoFでしか実現できない(XYZ軸の回転のみ検出する)のが難点ですが、そこはアイデアで乗り切るしかありません。あとは、ブラウザとライブラリの進化に期待するしか!(他力本願寺
ペルソナ玲音の3Dモデルは、MagicaVoxelとBlenderを利用し自作しました。モデルの形式ですが、今回はglTFを利用します。glTFだとモーションまで含んだ3Dモデルとして扱えるため、ただ3Dモデルが「そこにある」だけでなく「動く」ので、UXの観点から非常に有利です。
3Dモデルの作り方は割愛しますが、簡単に紹介すると下記のような手順で動く3Dモデルを作成可能です。というか、これ書くだけで1つ記事ができそうな内容ではあるのでちょっと割愛しないとテキスト量が大変なことに_( _´ω`)_ペショ
ちなみに、MixAmoからダウンロードする際は、FBX形式じゃなくてもBlenderにはインポートできると思いますが、とりあえずFBXを選択しておけば問題ないと思います。
実際に記述したコードは下記のHTMLソースだけです。HTMLと3Dモデルだけ準備すればARが実装できるのは、本当にA-Frame様様ですね。
<html>
<head>
<script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script>
<script src="https://jeromeetienne.github.io/AR.js/aframe/build/aframe-ar.js"></script>
<script src="https://cdn.jsdelivr.net/gh/donmccurdy/aframe-extras@v6.1.1/dist/aframe-extras.min.js"></script>
</head>
<body>
<a-scene embedded arjs="debugUIEnabled:false;" renderer="gammaOutput: true;" vr-mode-ui="enabled: false">
<a-assets>
<a-asset-item id="model" src="persona_lain_blender.glb"></a-asset-item>
</a-assets>
<a-entity scale="100 100 100" position="0 0.4 -3" animation-mixer="clip:*" gltf-model="#model" visible="true">
</a-entity>
<a-light type="ambient" color="#ffffff"></a-light>
<a-light type="point" intensity="2" position="0 4 0"></a-light>
</a-scene>
</body>
</html>
本来、glTFやFBXをそのまま3DモデルとしてAR空間上に出現させる場合、A-Frame単体では実現できません。じゃあどうしているかというと、A-Frame extrasという、A-Frameの拡張機能を利用します。このアドオンを導入することで、glTFの実装が可能になります。
ちなみに、当初FBX形式を利用しAR実装を目指していた際、「inflate.min.js
がないよー」とブラウザのコンソールでエラーが表示されました。エラーメッセージはError: FBXLoader: Import inflate.min.js from https://github.com/imaya/zlib.js
というもの。このinflate.min.js
がNPMやCDN上に見当たらなかったため、https://github.com/imaya/zlib.jsから該当のファイルを単体でダウンロードして任意のフォルダに保存し、参照しました。ところがglTFファイルの利用時には、上記のinflate.min.js
が必要ないらしくコメントアウトしても動作に影響がありませんでした。なので、FBXを利用しないのであれば、このファイルは不要っぽいです。
各設定値の内容は下記の通りです。
vr-mode-ui="enabled: false"
は、ブラウザの画面下に現れるVR用画面のためのボタンを非表示にする。renderer="gammaOutput: true;"
は下側のa-light
と同様に、3Dモデルに対する光の調節を行っている。これがないと、3Dモデルがすこぶる暗く表示されてしまうため。理由はちゃんと調べていないが、とりあえずこの設定をするとまともに見られるようになった。a-entity
でscale
の設定をX軸Y軸Z軸の全方向で100倍しているが、これはもとのglTFの3Dモデルがなぜかめちゃくちゃ小さいため。Blenderでインポートしたときも「なんか小さいなー」とは思っていたのだが、glTFにエクスポートしたら米粒みたいに小さかった。そのまま表示させたら、どこにいるのかわからないくらい小さい。今回はとりあえずスケールアップすることでなんとかした。多分Blenderにインポートした際、モデルの値をちゃんと設定しておくべきだったのだろうが・・・3Dモデルの設定は謎が多い。position
の値は適当。とりあえずカメラ位置よりも3Dモデルを奥側に配置させるため、Z軸に負の数を設定している。rotation
は設定なし。animation-mixer
はモーション設定のあるglTFでは必須。ただし、MixAmoで出力したFBXはモーション名がいまいち不明なので、clip:*
にしてどんなモーションでも実行するような設定にしてある。多分これはBlenderでの設定が必要な部分だと思う。visible
の設定って必要なのか、というところだが(デフォルト値でTrueになってると普通は思う)とりあえず設定済み。これだけ書けば動作します。すげぇ。
これまでの実装では、ただ3Dモデルを表示するだけでした。ですが、A-Frameはエンティティに対してアニメーションを設定できます。というわけで、アニメーションを追加してみました。
<html>
<head>
<script src="https://aframe.io/releases/1.0.4/aframe.min.js"></script>
<script src="https://jeromeetienne.github.io/AR.js/aframe/build/aframe-ar.js"></script>
<script src="https://cdn.jsdelivr.net/gh/donmccurdy/aframe-extras@v6.1.1/dist/aframe-extras.min.js"></script>
</head>
<body>
<a-scene embedded arjs="debugUIEnabled:false;" renderer="gammaOutput: true;" vr-mode-ui="enabled: false">
<a-assets>
<a-asset-item id="persona_lain_waving" src="persona_lain_waving.glb"></a-asset-item>
<a-asset-item id="chibi_navi" src="lain_chibi_navi.glb"></a-asset-item>
</a-assets>
<a-entity scale="1 1 1" rotaion="0 0 0" position="0 0.4 -3" animation-mixer="clip:*"
gltf-model="#persona_lain_waving" visible="true"
animation="property: position; from: 0 0.5 -3; to: 0 0.8 -3; dir: alternate; dur: 1800; easing: easeInOutQuad; loop: true">
</a-entity>
<a-entity scale="0.2 0.2 0.2" rotation="-45 -45 0" animation-mixer="clip:*" gltf-model="#chibi_navi"
visible="true"
animation="property: position; from: 0.1 0.2 -3.5; to: 0.1 0.5 -3.5; dir: alternate; dur: 2300; easing: easeInOutQuad; loop: true">
</a-entity>
</a-obj-model>
<a-light type="ambient" color="#ffffff"></a-light>
<a-light type="point" intensity="2" position="0 4 0"></a-light>
</a-scene>
</body>
</html>
相変わらずHTMLしか書いてません。JSなんてこれっぽっちも書いてないのに動作するA-Frameマジ神。なお、さっきのコードと比べてわかるとおり、エンティティのスケールが100倍とかじゃないです。これは、モデル設定をBlender側で修正してから実装しているためです。
改良前を比較すると、表示する3Dモデルを増やしつつアニメーションを設定しています。アニメーションにおける各設定値の内容は下記の通りです。
position
なので、3Dモデルの位置が変化する。position
。エンティティの初期位置よりY時を下に設定するとモデルの下部分が欠けるため、Y軸の位置は0.4より上に設定している。position
。normal
だとfromからtoへの一方通行。alternate
だと、fromとtoを交互に往復する。reverse
はtoからfromへ一方通行。そんなわけでペルソナ玲音を召喚するARを、A-Frameで実装してみました。
モダンなブラウザが手元にあるなら、URLさえ渡せばすぐ動作可能なのはやっぱり最大のメリットですねぇ。
それと、glTF単体でモーション設定するのもいいけど、A-Frameのアニメーションも活用したいものです・・・いやまぁ、アニメーション設定でどうにかできる動きには限界があるんで、派手目なモーションのためにはやっぱりMixAmoなんかでモーション設定するのは必須、って感じがするのは致し方ないところ。とはいえ、単純な上下運動とかのアニメーションはA-Frameで書いた方が早いし、JavaScriptで書き換えられたりするので使い勝手がいいので、使い所なんですね。