【Three.js】マウスで触れたオブジェクトの名前を表示する(ピッキング)

スポンサーリンク
Three.js

マウスポインタが指すオブジェクトの名前を表示したい

こういったお悩みを解決いたします。

マウスを使う3Dコンテンツにおいて、ピッキング機能はあれば嬉しい機能の一つですよね。

名前だけでなくオブジェクトの状態や他プレイヤーの情報など、幅広く表示することができます。

今回は簡単なサンプルとしてオブジェクトにつけた名前を文字列として表示します。

ソースコードとデモを載せていますので、ぜひ参考にしてみてください。

スポンサーリンク

ピッキングの流れ

以下のようなステップでピッキングを実装します。

  1. マウスポインタが動くたび、ポインタの座標を正規化し光線発射方向ベクトルを生成する
  2. 方向ベクトルにしたがってカメラから光線を出し、オブジェクトに触れていないかチェックする
  3. 触れていた場合、そのマウスの位置に情報(今回は名前)を描画する

これを頭に入れたうえでソースコードを読むと、理解しやすいと思います。

スポンサーリンク

ピッキングのソースコードとデモを確認してみる

早速ですが、ピッキングのソースコードとデモを以下に示します。

<!DOCTYPE html>
<html>
  <head>
    <title>three.js Sample</title>
    <meta charset="utf-8">
    <script src="./three.js-master/build/three.min.js"></script><!--three.jsライブラリの読み込み-->
    <script src="./three.js-master/examples/js/controls/PointerLockControls.js"></script><!--PointerLockControls.jsの読み込み-->
  </head>
  <body style="overflow: hidden;"><!--スクロールバーが出る方はoverflowをhiddenに設定すると消えます-->
    <div id="picking-info" style="position: absolute; color: white; background-color: black; font-size: x-large;"></div>
    <script>
      const scene = new THREE.Scene();  //シーンを作成
      const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 5000);  //カメラを作成
      const renderer = new THREE.WebGLRenderer(); //レンダラーを作成
      const boxGeometry = new THREE.BoxGeometry(100, 100, 100); //boxの形状データ
      const boxMaterial = new THREE.MeshNormalMaterial(); //boxの材質(マテリアル)情報
      const box1 = new THREE.Mesh(boxGeometry, boxMaterial); //形状と材質から実際の3Dオブジェクトを生成
      const box2 = new THREE.Mesh(boxGeometry, boxMaterial);
      const box3 = new THREE.Mesh(boxGeometry, boxMaterial);
      const raycaster = new THREE.Raycaster();  //ピッキング用の光線を出す
      let pickingObjects = [];  //ピッキング対象のオブジェクトを管理
      init();
      animate();

      function init(){    //初期化用関数
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.shadowMap.enabled = true;
        renderer.shadowMap.type = THREE.BasicShadowMap;
        document.body.appendChild(renderer.domElement); //canvas要素をbodyタグに追加
        camera.position.set(0, 0, 500);
        box1.position.set(-200, 0, 0);
        box2.position.set(0, 0, 0);
        box3.position.set(200, 0, 0);
        box1.name = 'box1';
        box2.name = 'box2';
        box3.name = 'box3';
        scene.add(box1); scene.add(box2); scene.add(box3);
        pickingObjects.push(box1);
        pickingObjects.push(box2);
        pickingObjects.push(box3);
        renderer.domElement.addEventListener('mousemove', onMouseMove, false);
      }

      function animate(){
        renderer.render(scene, camera);
        requestAnimationFrame(animate); //毎フレーム呼び出すことで描画
      }

      function onMouseMove(e){
        let mouseX = (e.clientX / window.innerWidth) * 2 - 1; //現在のマウスの座標を正規化
        let mouseY = (e.clientY / window.innerHeight) * -2 + 1;
        let pickVec = new THREE.Vector2(mouseX, mouseY);  //ピッキングのための光線を出す方向を表すベクトル
        let pickedObject = checkPickedObject(pickVec);
        drawPickingInfo(new THREE.Vector2(e.clientX, e.clientY), pickedObject);
      }

      function checkPickedObject(pickVec){ //現在、マウスが触れているオブジェクトがあるかどうか検査
        raycaster.setFromCamera(pickVec, camera); //カメラからpickVecの方向に光線を出す
        let intersects = raycaster.intersectObjects(pickingObjects);  //引数としてピッキングを検知したいオブジェクトを渡す.返り値は光線が触れたオブジェクトの情報
        if(intersects.length <= 0) return null;
        let pickedObject = intersects[0].object;
        return pickedObject;
      }

      function drawPickingInfo(drawPos, object){  //(Vector2, pickedObject) ピッキング時に情報を描画する
        let pickingInfo_div = document.getElementById("picking-info");
        if(object === null){
          pickingInfo_div.textContent = '';
          return;
        }
        pickingInfo_div.style.left = drawPos.x + 'px';  //マウスの位置に描画する
        pickingInfo_div.style.top = drawPos.y + 'px';
        pickingInfo_div.textContent = object.name;
      }

    </script>
  </body>
</html>

デモを見たい方はこちらをクリック(ページは遷移しません) ⇒

オブジェクトにマウスで触れると、その位置に名前が表示されたのが確認できるかと思います。

各行で何をしているかは、ソースコード内のコメントを参考にしてみてください。

一見とっつきにくいコードかもしれませんが、わりと単純なコードになっています。

onMouseMoveはマウスが動くたび呼ばれます。

その中で、ピッキングを検知するcheckPickedObject、ピッキング情報を描画するdrawPickingInfoを実行しています。

情報を描画する位置を変えたい!!

という方は、drawPickingInfoをいじれば簡単に変えられます。表示する情報も同様ですね。

上記ソースコードで動作確認はできているので動くかと思いますが、何か問題がございましたら気軽にコメントでお知らせください。

まとめ

いかがでしたでしょうか。

当記事では、

マウスで触れたオブジェクトの情報を表示する方法を解説いたしました。

ぜひ、参考にしていただければ幸いです。

以上です。

コメント

タイトルとURLをコピーしました