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

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

AR.js + Three.jsを使ったImage Trackingを検証する 📷

ar-js-org.github.io

AR.jsのドキュメント にはA-Frame用を使ったコードが記載されているのですが、Three.jsを使った実装も検証します。

結論

先に結論を書いておきます。
A-Frame を使っても Three.js を使ってもイメージトラッキングの実装は可能でした。
ただし、現時点では実戦で使用するのはちょっと厳しいかな。という印象です。

  • AFrameでもThree.jsでも実装可能
  • どちらもマーカーに対するARオブジェクトの位置が安定しない(かなりガクガクする)
  • THREEx.ArSmoothedControls は使用できない
  • PCとスマホでARオブジェクトの表示位置がかなりズレる

A-Frameを使ったサンプル

github.com

Three.jsを使ったサンプル

github.com

Three.jsでの実装

blog.kimizuka.org

マーカーを使った実装をちょっと変更するだけでOKかと思いきや、微妙なはまりどころがあったので、コメントで補足しておきます。

ソースコード

index.html(全文)
<html>
<head>
  <title>three.js + ar.js</title>
  <meta name="viewport" content="width=device-width, viewport-fit=cover, shrink-to-fit=no" />
  <style>
    * {
      margin: 0; padding: 0;
    }

    .wrapper {
      position: relative;
      overflow: hidden;
    }
  </style>
</head>
<body>
  <div class="wrapper">
    <canvas></canvas>
  </div>
  <script src="https://unpkg.com/three@0.127.0/build/three.min.js"></script>
  <script src="https://raw.githack.com/AR-js-org/AR.js/3.3.3/three.js/build/ar-nft.js"></script><!--❶ イメージトラッキング用のスクリプトに変更-->
  <script>
    const renderer = new THREE.WebGLRenderer({
      canvas: document.querySelector('canvas'),
      antialias: true,
      alpha: true
    });
    const camera = new THREE.PerspectiveCamera();
    const scene = new THREE.Scene();
    const markerRoot = new THREE.Group();
    const arToolkitContext = new THREEx.ArToolkitContext({
      detectionMode: 'mono'
    });
    const arToolkitSource = new THREEx.ArToolkitSource({
      sourceType: 'webcam'
    });
    const arMarkerControls = new THREEx.ArMarkerControls(arToolkitContext, camera, {
      type: 'nft', // 'nft'に変更
      descriptorsUrl : 'marker/filename', // ❷ https://carnaux.github.io/NFT-Marker-Creator/ で作成
      changeMatrixMode: 'cameraTransformMatrix'
    });

    renderer.setSize(window.innerWidth, window.innerHeight);
    scene.add(camera); // ❸ カメラをシーンに追加
    
    window.addEventListener('resize', handleResize, {
      passive: true
    });

    window.addEventListener('arjs-nft-loaded', (evt) =>{
      console.log(evt);
    });

    arToolkitContext.init(() => {
      camera.projectionMatrix.copy(arToolkitContext.getProjectionMatrix());
    });

    arToolkitSource.init(() => {
      document.querySelector('.wrapper').appendChild(arToolkitSource.domElement);
      setTimeout(() => handleResize(), 400);
    });

    scene.visible = false;
    scene.add(markerRoot);

    const cube = new THREE.Mesh(
      new THREE.BoxGeometry(100, 100, 100), // ❹ 大きめに設定
      new THREE.MeshNormalMaterial()
    );

    cube.position.set(0, 0, 0); // ❹ 一旦、原点に表示

    markerRoot.add(cube);

    renderer.setAnimationLoop((delta) => {
      if (arToolkitSource.ready) {
        arToolkitContext.update(arToolkitSource.domElement);
      }

      scene.visible = camera.visible; // ❺ 自力で表示・非表示を切り替える
      renderer.render(scene, camera);
    });

    function handleResize() {
      if (arToolkitSource.ready) {
        arToolkitSource.onResize();
        arToolkitSource.copySizeTo(renderer.domElement);
      }

      renderer.setPixelRatio(window.devicePixelRatio);
    }
  </script>
</body>
</html>

解説

❷ fset・fset3・isetの作成

https://carnaux.github.io/NFT-Marker-Creator/ にトラッキングしたい画像をアップして、fset・fset3・isetをダウンロードします。

  • filename.fset
  • filename.fset3
  • filename.iset

の3つのファイルが生成されるので、descriptorsUrlには3つのファイルを収納されているディレクトリと、filenameを記述します。

carnaux.github.io

❸ カメラの追加

マーカー型のARの場合は、カメラをシーンに追加せずとも動作するのですが、イメージトラッキングの場合は必須でした。

❹ オブジェクトの大きさ・ポジション

オブジェクトが小さすぎると目視での確認が困難なので、大きめに表示します。
公式のexample でもポジションをダイナミック(model.position.z = -100)に設定しています。

github.com

また、ポジションに関しては example だと、nft.detailの幅・高さ・dpiを元に設定しているのですが、

window.addEventListener('arjs-nft-init-data', function(nft) {
  console.log(nft);
  var msg = nft.detail;
  model.position.y = (msg.height / msg.dpi * 2.54 * 10)/2.0; //y axis?
  model.position.x = (msg.width / msg.dpi * 2.54 * 10)/2.0; //x axis?
});

?がついていること、exampleでもPC、スマホでオブジェクトの位置が大きくずれることから、一旦、原点(0,0,0)に設定しました。

❺ シーンの表示非表示を切り替える

マーカー型だと自動で行われる処理ですが、イメージトラッキングの場合、自力で表示・非表示の切り替えが必要でした。

DEMO

develop.kimizuka.org

こちらにイメージトラッキングのサンプルをアップしました。
本の表紙をトラッキングできるか試したかったので、下記の画像を認識するように設定しています。

https://m.media-amazon.com/images/I/51hjJ-AlVNL._SX343_BO1,204,203,200_.jpg

また、もしも 手元に帯付きの本 がある場合は、実物の本も認識するはずです。