かつて、 A-Frameでマーカーの検知イベントを使ったこと がありましたが、今回はThree.jsで実装してみます。
といっても、A-Frameも内部ではThree.jsを使っているので、実装方法はほとんど変わりません。
ただし、認識時のイベント(markerFound)は、微妙に仕様が異なり、認識が切れた際のイベント(markerLost)は 実装されていません 。
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」と表示されています。
markerLostを自前実装せず、markerFoundをそのまま使っているバージョンは こちら です。
どちらも、このマーカーを認識するようにしています。