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

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

THREE.Raycasterを使って、直線上にオブジェクトが存在するかを調べる 🔍

以前、Three.jsでクリックされたオブジェクトを判定する際に使った、THREE.Raycasterを再び調査しました。

blog.kimizuka.org

threejs.org

クリックされたオブジェクトの判定では、Raycaster.setFromCameraというメソットを使い、クリックされた点の直線上に存在するオブジェクトを導き出しましたが、今回は、Raycaster.setRaycaster.setに基準点と方向を渡すことで、その直線上にオブジェクトが存在するか調べます。


DEMO

キーボードの矢印でCubeの位置を調整できるのですが、直線上に存在する時のみ左上に「HIT」と表示されます。
赤外線センサに引っかかるスパイのようなイメージです。
iframeで埋め込むとページがスクロールしてしまって使いにくいので、JSFiddleで確認するのがおすすめです。

jsfiddle.net


ソースコード(抜粋)

const renderer = new THREE.WebGLRenderer({
  canvas: document.querySelector('canvas'),
  antialias: true,
  alpha: true
});

renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);

const scene = new THREE.Scene();

const camera = new THREE.PerspectiveCamera(45)

camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
camera.position.set(8, 8, 8);
camera.lookAt(new THREE.Vector3(0, 0, 0));

scene.add(camera);

const cube = new THREE.Mesh(
  new THREE.BoxGeometry(1, 1, 1),
  new THREE.MeshNormalMaterial()
);

scene.add(cube);

const raycaster = new THREE.Raycaster( // Raycaster.setを使わず、コンストラクタに基準点(第一引数)と方向(第二引数)を渡す
  new THREE.Vector3(-4, .25, -2),
  new THREE.Vector3(1, 0, 0),
  0,
  8
);

const line = new THREE.Line( // 確認用にRaycasterと同じ位置にLineを引く
  new THREE.BufferGeometry().setFromPoints([
    new THREE.Vector3(-4, .25, -2),
    new THREE.Vector3(4, .25, -2),
  ]),
  new THREE.MeshNormalMaterial()
);

scene.add(line);

renderer.setAnimationLoop(() => {
  renderer.render(scene, camera);
  const intersects =raycaster.intersectObjects(scene.children); // Raycaster上にあるインスタンスを取得

  if (1 < intersects.length) { // Raycasterには常にLineが存在するので、1以上のときがCubeが存在する時
    intersects.forEach(({ object }) => {
      if (object.type !== 'Line') { // Lineを無視
        document.querySelector('p').innerText = 'HIT!';
      }
    });
  } else {
    document.querySelector('p').innerText = '';
  }
});

document.addEventListener('keydown', ({ key }) => {
  switch(key) {
    case 'ArrowLeft':
      cube.position.x -= .1;
      break;
    case 'ArrowRight':
      cube.position.x += .1;
      break;
    case 'ArrowUp':
      cube.position.z -= .1;
      break;
    case 'ArrowDown':
      cube.position.z += .1;
      break;
  }
});