#概要
A-FrameとAR.jsによるWebARにおいて、マーカーの検出と同時にアニメーションを再生する必要があったため、その備忘録です。
AFRAME.registerComponent
でマーカの検出/非検出をイベントとして登録し、そのイベントが呼ばれたタイミングでアニメーションを再生/停止します。
動画はワイヤーフレームのboxがHiroマーカーから5秒かけて上昇するアニメーションの繰り返しですが、マーカーを検出したタイミングでアニメーションが初期位置から再生されています。
#環境
A-Frame -> 0.8.0
AR.js -> 1.6.2
#a-animation
回転や移動等の簡単なアニメーションは、A-frameのa-animation
タグで実現できます。
下記の例では、ワイヤーフレームのboxがHiroマーカーから5秒かけて上昇するアニメーションが繰り返し再生されます。
<!doctype HTML>
<html>
<script src="https://aframe.io/releases/0.8.0/aframe.min.js"></script>
<script src="https://cdn.rawgit.com/jeromeetienne/AR.js/1.6.2/aframe/build/aframe-ar.js"> </script>
<body style="margin : 0px; overflow: hidden;">
<a-scene embedded arjs>
<a-marker preset="hiro">
<a-box position="0 0.5 0" wireframe="true">
<a-animation attribute="position" from="0 0.5 0" to="0 2.5 0" dur="5000" repeat="indefinite">
</a-animation>
</a-box>
</a-marker>
<a-entity camera></a-entity>
</a-scene>
</body>
</html>
しかし、アニメーションはページの読み込みと同時に再生が開始されるため、boxが表示されていない状態でも位置は移動しています。
そのため、Hiroマーカーを検出したタイミングによって、最初にboxが表示される位置が異なってしまいます。
ループするアニメーションの場合はさほど問題にはなりませんが、アニメーションを最初から再生して表示したい場合などには適していません。
アニメーションを任意のタイミングで再生する方法として、a-animation
のbegin
及びend
属性があります。
下記に示す公式の例では、アニメーションを開始するイベントとして、begin
属性に'fade'
というイベント名を指定しています。
再生にはアニメーションが設定されている親要素(ここではid="fading-cube"
を持つa-entity
)を取得し、emit('fade')
と指定されたイベントを発火することでアニメーションを開始することができます。
<a-entity id="fading-cube" geometry="primitive: box" material="opacity: 1">
<a-animation attribute="material.opacity" begin="fade" to="0"></a-animation>
</a-entity>
document.querySelector('#fading-cube').emit('fade');
したがって、「マーカーを検出したタイミング」を取得してイベントを発火する事で、マーカーの検出と同時にアニメーションを再生する事ができます。
#マーカーを検出してアニメーションを再生
マーカーの検出/非検出をイベントとしてトリガーする方法はAR.jsに用意されており、こちらに実装例があります。
これらを組み合わせて、マーカーの検出と同時にアニメーションを再生し、マーカーを見失うとアニメーションを停止する機能を実装しました。
マーカーを再検出した場合には、アニメーションは再度頭から再生されます。
<!doctype HTML>
<html>
<script src="https://aframe.io/releases/0.8.0/aframe.min.js"></script>
<script src="https://cdn.rawgit.com/jeromeetienne/AR.js/1.6.2/aframe/build/aframe-ar.js"> </script>
<script>
AFRAME.registerComponent('registerevents', {
init: function () {
var marker = this.el;
// マーカーを検出したイベントの登録
marker.addEventListener('markerFound', function () {
var markerId = marker.id;
console.log('markerFound', markerId);
// アニメーションの開始
document.querySelector('#box').emit('markerfound');
});
// マーカーを見失ったイベントの登録
marker.addEventListener('markerLost', function () {
var markerId = marker.id;
console.log('markerLost', markerId);
// アニメーションの停止
document.querySelector('#box').emit('markerlost');
});
}
});
</script>
<body style="margin : 0px; overflow: hidden;">
<a-scene embedded arjs>
<a-marker preset="hiro" id="marker-hiro" registerevents>
<a-box id="box" position="0 0.5 0" wireframe="true">
<a-animation attribute="position" from="0 0.5 0" to="0 2.5 0" dur="5000" repeat="indefinite" begin="markerfound" end="markerlost">
</a-animation>
</a-box>
</a-marker>
<a-entity camera></a-entity>
</a-scene>
</body>
</html>
こちらから実行する事ができます。
対象のマーカーのa-marker
タグにregisterevents
属性を追加する事で、マーカーの検出/非検出のタイミングをイベントとして登録する事ができます。
今回はマーカーを検出したイベントmarkerFound
をトリガーに、アニメーションを再生するイベント'markerFound'
を、マーカーを見失ったイベントmarkerLost
をトリガーに、アニメーションを停止するイベント'markerlost'
を発火する事で、マーカーの検出/非検出に応じてアニメーションを再生/停止しています。
#まとめ
AR.jsのマーカーの検出イベントと、a-animation
のbegin
/end
属性を組み合わせる事で、マーカーの検出/非検出をトリガーにアニメーションの再生/停止を制御する事ができました。
この他にも、マーカーを検出して音声を再生したり、javascriptの実行結果によって特定のアニメーションを再生するなどの応用ができると思います。
#参考
https://github.com/jeromeetienne/AR.js/blob/master/aframe/examples/marker-events.html
https://aframe.io/docs/0.8.0/core/animations.html
https://jsfiddle.net/donmccurdy/tzm4q9n7/