みかづきブログ・カスタム

基本的にはちょちょいのほいです。

AR.js + Three.jsでマーカー認識時にコールバックイベントを発火させる(markerFoundの調整、markerLostの自作) 🔥

かつて、 A-Frameでマーカーの検知イベントを使ったこと がありましたが、今回はThree.jsで実装してみます。

blog.kimizuka.org


といっても、A-Frameも内部ではThree.jsを使っているので、実装方法はほとんど変わりません。
ただし、認識時のイベント(markerFound)は、微妙に仕様が異なり、認識が切れた際のイベント(markerLost)は 実装されていません

github.com

markerFound

A-FrameのmarkerFoundイベントマーカー認識時に一度だけ発火(markerLost時にリセット)される仕様ですが、Three.jsのmarkerFoundはマーカーが認識されている限り発火し続けます。

JavaScript(抜粋)

const arMarkerControls = new THREEx.ArMarkerControls(arToolkitContext, markerRoot, {
  type: 'pattern',
  patternUrl: 'pattern.patt'
});

// マーカーが認識されている限り発火し続ける
arMarkerControls.addEventListener('markerFound', () => {
  console.log('Found');
  document.querySelector('.console').innerText = 'Found';
});

A-Frameの挙動に合わせたい場合は、ReactのuseState、useEffectのような仕組みを使うのが簡単ですが、すべて自前で賄いたい場合は、マーカーの状態を変数に収納しておく必要があります。
が。先にmarkerLostを自前で実装した方がシンプルになるので、一旦後回しにします。

markerLost(自作)

Three.jsにはmarkerLostが実装されていないので、dispatchEventで発火させます。

JavaScript(抜粋)

const arMarkerControls = new THREEx.ArMarkerControls(arToolkitContext, markerRoot, {
  type: 'pattern',
  patternUrl: 'pattern.patt'
});
const lostDelay = 100;

// Three.jsには実装されていないので発火しない
arMarkerControls.addEventListener('markerLost', () => {
  console.log('Lost');
  document.querySelector('.console').innerText = 'Lost';
});

arMarkerControls.addEventListener('markerFound', () => {
  console.log('Found');
  document.querySelector('.console').innerText = 'Found';

  clearTimeout(timer);
  timer = setTimeout(() => arMarkerControls.dispatchEvent({ type: 'markerLost' }),  lostDelay); // マーカーを見失ってから0.1秒後にmarkerLostを発火させる
});

markerFound(カスタム)

markerLostが発火するようになれば、マーカーの状態を変数に収納することで、markerFoundの挙動をA-Frameに合わせることができます。

JavaScript(抜粋)

const arMarkerControls = new THREEx.ArMarkerControls(arToolkitContext, markerRoot, {
  type: 'pattern',
  patternUrl: 'pattern.patt'
});
const lostDelay = 100;
let markerState = 'lost'; // markerStateを更新

// Three.jsには実装されていないので発火しない
arMarkerControls.addEventListener('markerLost', () => {
  console.log('Lost');
  document.querySelector('.console').innerText = 'Lost';
  markerState = 'lost';
});

arMarkerControls.addEventListener('markerFound', () => {
  // markerStateがlostの時のみ実行する
  if (markerState === 'lost') {
    console.log('Found');
    document.querySelector('.console').innerText = 'Found';
  }

  markerState = 'found'; // markerStateを更新

  clearTimeout(timer);
  timer = setTimeout(() => arMarkerControls.dispatchEvent({ type: 'markerLost' }),  lostDelay); // マーカーを見失ってから0.1秒後にmarkerLostを発火させる
});

DEMO

ちょっとわかりにくいですが、右上に「Found」「Lost」と表示されています。

develop.kimizuka.org

markerLostを自前実装せず、markerFoundをそのまま使っているバージョンは こちら です。

develop.kimizuka.org

どちらも、このマーカーを認識するようにしています。


追記

イメージトラッキング版も検証しました。

blog.kimizuka.org